Taking a snapshot of the AutoCAD model (take 2)
In this previous post, we looked at some code to do a programmatic snapshot of AutoCAD's modelspace, saving the results to an image file.
From the discussion that followed, I realised that the code had an undesired (and unnecessary) side-effect of creating a new 3D GS View and leaving the modelspace with that view active. GS Views in AutoCAD 2007 have grey backgrounds by default, and so this change can be quite disturbing for users. The only reason we created the GS View in the first place (if one didn't already exist), was to use it to query the view position/target/up vector/field width and height and apply it to our new view. Thankfully it seems this can also be determined directly from the viewport.
So rather than calling GetGSView() and using the returned view to get that information, we now simply call SetViewFromViewport() specifying the viewport number held in CVPORT, and the graphics system manager for that document handles the rest.
Here's the updated C# code, which appears to achieve the same goals without the side-effect. Check line 124 for the new code, a few extraneous lines around it having been removed:
1 using Autodesk.AutoCAD.ApplicationServices;
2 using Autodesk.AutoCAD.DatabaseServices;
3 using Autodesk.AutoCAD.EditorInput;
4 using Autodesk.AutoCAD.GraphicsInterface;
5 using Autodesk.AutoCAD.GraphicsSystem;
6 using Autodesk.AutoCAD.Runtime;
7 using Autodesk.AutoCAD.Interop;
8 using System.Drawing;
9
10 namespace OffscreenImageCreation
11 {
12 public class Commands
13 {
14 [CommandMethod("OSS")]
15 static public void OffscreenSnapshot()
16 {
17 CreateSphere();
18 SnapshotToFile(
19 "c:\\sphere-Wireframe2D.png",
20 VisualStyleType.Wireframe2D
21 );
22 SnapshotToFile(
23 "c:\\sphere-Hidden.png",
24 VisualStyleType.Hidden
25 );
26 SnapshotToFile(
27 "c:\\sphere-Basic.png",
28 VisualStyleType.Basic
29 );
30 SnapshotToFile(
31 "c:\\sphere-ColorChange.png",
32 VisualStyleType.ColorChange
33 );
34 SnapshotToFile(
35 "c:\\sphere-Conceptual.png",
36 VisualStyleType.Conceptual
37 );
38 SnapshotToFile(
39 "c:\\sphere-Flat.png",
40 VisualStyleType.Flat
41 );
42 SnapshotToFile(
43 "c:\\sphere-Gouraud.png",
44 VisualStyleType.Gouraud
45 );
46 SnapshotToFile(
47 "c:\\sphere-Realistic.png",
48 VisualStyleType.Realistic
49 );
50 }
51
52 static public void CreateSphere()
53 {
54 Document doc =
55 Application.DocumentManager.MdiActiveDocument;
56 Database db = doc.Database;
57 Editor ed = doc.Editor;
58
59 Transaction tr =
60 doc.TransactionManager.StartTransaction();
61 using (tr)
62 {
63 BlockTable bt =
64 (BlockTable)tr.GetObject(
65 db.BlockTableId,
66 OpenMode.ForRead
67 );
68 BlockTableRecord btr =
69 (BlockTableRecord)tr.GetObject(
70 bt[BlockTableRecord.ModelSpace],
71 OpenMode.ForWrite
72 );
73 Solid3d sol = new Solid3d();
74 sol.CreateSphere(10.0);
75
76 const string matname =
77 "Sitework.Paving - Surfacing.Riverstone.Mortared";
78 DBDictionary matdict =
79 (DBDictionary)tr.GetObject(
80 db.MaterialDictionaryId,
81 OpenMode.ForRead
82 );
83 if (matdict.Contains(matname))
84 {
85 sol.Material = matname;
86 }
87 else
88 {
89 ed.WriteMessage(
90 "\nMaterial (" + matname + ") not found" +
91 " - sphere will be rendered without it.",
92 matname
93 );
94 }
95 btr.AppendEntity(sol);
96
97 tr.AddNewlyCreatedDBObject(sol, true);
98 tr.Commit();
99 }
100 AcadApplication acadApp =
101 (AcadApplication)Application.AcadApplication;
102 acadApp.ZoomExtents();
103 }
104
105 static public void SnapshotToFile(
106 string filename,
107 VisualStyleType vst
108 )
109 {
110 Document doc =
111 Application.DocumentManager.MdiActiveDocument;
112 Editor ed = doc.Editor;
113 Database db = doc.Database;
114 Manager gsm = doc.GraphicsManager;
115
116 // Get some AutoCAD system variables
117 int vpn =
118 System.Convert.ToInt32(
119 Application.GetSystemVariable("CVPORT")
120 );
121
122 using (View view = new View())
123 {
124 gsm.SetViewFromViewport(view, vpn);
125
126 // Set the visual style to the one passed in
127 view.VisualStyle = new VisualStyle(vst);
128
129 Device dev =
130 gsm.CreateAutoCADOffScreenDevice();
131 using (dev)
132 {
133 dev.OnSize(gsm.DisplaySize);
134
135 // Set the render type and the background color
136 dev.DeviceRenderType = RendererType.Default;
137 dev.BackgroundColor = Color.White;
138
139 // Add the view to the device and update it
140 dev.Add(view);
141 dev.Update();
142
143 using (Model model = gsm.CreateAutoCADModel())
144 {
145 Transaction tr =
146 db.TransactionManager.StartTransaction();
147 using (tr)
148 {
149 // Add the modelspace to the view
150 // It's a container but also a drawable
151 BlockTable bt =
152 (BlockTable)tr.GetObject(
153 db.BlockTableId,
154 OpenMode.ForRead
155 );
156 BlockTableRecord btr =
157 (BlockTableRecord)tr.GetObject(
158 bt[BlockTableRecord.ModelSpace],
159 OpenMode.ForRead
160 );
161 view.Add(btr, model);
162 tr.Commit();
163 }
164 // Take the snapshot
165 Rectangle rect = view.Viewport;
166 using (Bitmap bitmap = view.GetSnapshot(rect))
167 {
168 bitmap.Save(filename);
169 ed.WriteMessage(
170 "\nSnapshot image saved to: " +
171 filename
172 );
173 // Clean up
174 view.EraseAll();
175 dev.Erase(view);
176 }
177 }
178 }
179 }
180 }
181 }
182 }
You can also download the .cs file from here.
April 18, 2007 in AutoCAD, AutoCAD .NET, Graphics system | Permalink | Comments (8) | TrackBack
Taking a snapshot of the AutoCAD model using .NET
This topic is a follow-up to the previous post dealing with offscreen rendering, and was suggested (and is based on code provided) by Fenton Webb, a member of DevTech Americas who has just moved across to San Rafael. Fenton was until recently part of DevTech EMEA, working from the UK.
The basic technique is similar to the one used in the previous post: we use the graphics system to create an "offscreen device", which we then set up and request to create a snapshot of our model. This can work on graphical objects stored in any AutoCAD database, but in this case we use it to capture an image of the contents of the active drawing's modelspace (after, once again, adding a sphere to it).
To spice up the results a little, I added the option to specify a particular visual style for the output. I've inserted the created images at the bottom (as before, you will need to add a particular material to the current drawing in order to get exactly the same results I as I have).
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.GraphicsSystem;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.Interop;
using System.Drawing;
namespace OffscreenImageCreation
{
public class Commands
{
[CommandMethod("OSS")]
static public void OffscreenSnapshot()
{
CreateSphere();
SnapshotToFile(
"c:\\sphere-Wireframe2D.png",
VisualStyleType.Wireframe2D
);
SnapshotToFile(
"c:\\sphere-Hidden.png",
VisualStyleType.Hidden
);
SnapshotToFile(
"c:\\sphere-Basic.png",
VisualStyleType.Basic
);
SnapshotToFile(
"c:\\sphere-ColorChange.png",
VisualStyleType.ColorChange
);
SnapshotToFile(
"c:\\sphere-Conceptual.png",
VisualStyleType.Conceptual
);
SnapshotToFile(
"c:\\sphere-Flat.png",
VisualStyleType.Flat
);
SnapshotToFile(
"c:\\sphere-Gouraud.png",
VisualStyleType.Gouraud
);
SnapshotToFile(
"c:\\sphere-Realistic.png",
VisualStyleType.Realistic
);
}
static public void CreateSphere()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
Solid3d sol = new Solid3d();
sol.CreateSphere(10.0);
const string matname =
"Sitework.Paving - Surfacing.Riverstone.Mortared";
DBDictionary matdict =
(DBDictionary)tr.GetObject(
db.MaterialDictionaryId,
OpenMode.ForRead
);
if (matdict.Contains(matname))
{
sol.Material = matname;
}
else
{
ed.WriteMessage(
"\nMaterial (" + matname + ") not found" +
" - sphere will be rendered without it.",
matname
);
}
btr.AppendEntity(sol);
tr.AddNewlyCreatedDBObject(sol, true);
tr.Commit();
}
AcadApplication acadApp =
(AcadApplication)Application.AcadApplication;
acadApp.ZoomExtents();
}
static public void SnapshotToFile(
string filename,
VisualStyleType vst
)
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
Database db = doc.Database;
Manager gsm = doc.GraphicsManager;
// Get some AutoCAD system variables
int vpn =
System.Convert.ToInt32(
Application.GetSystemVariable("CVPORT")
);
// Get AutoCAD's GS view for this document...
View gsv =
doc.GraphicsManager.GetGsView(vpn, true);
// ... but create a new one for the actual snapshot
using (View view = new View())
{
// Set the view to be just like the one
// in the AutoCAD editor
view.Viewport = gsv.Viewport;
view.SetView(
gsv.Position,
gsv.Target,
gsv.UpVector,
gsv.FieldWidth,
gsv.FieldHeight
);
// Set the visual style to the one passed in
view.VisualStyle = new VisualStyle(vst);
Device dev =
gsm.CreateAutoCADOffScreenDevice();
using (dev)
{
dev.OnSize(gsm.DisplaySize);
// Set the render type and the background color
dev.DeviceRenderType = RendererType.Default;
dev.BackgroundColor = Color.White;
// Add the view to the device and update it
dev.Add(view);
dev.Update();
using (Model model = gsm.CreateAutoCADModel())
{
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// Add the modelspace to the view
// It's a container but also a drawable
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForRead
);
view.Add(btr, model);
tr.Commit();
}
// Take the snapshot
Rectangle rect = view.Viewport;
using (Bitmap bitmap = view.GetSnapshot(rect))
{
bitmap.Save(filename);
ed.WriteMessage(
"\nSnapshot image saved to: " +
filename
);
// Clean up
view.EraseAll();
dev.Erase(view);
}
}
}
}
}
}
}
And here are the images created by the OSS command, listed by their visual style type...
Wireframe2D:
Hidden:
Basic:
ColorChange:
Conceptual:
Flat:
Gouraud:
Realistic:
Update: an improved version of the above code is now available in this follow-up post.
April 9, 2007 in AutoCAD, AutoCAD .NET, Graphics system | Permalink | Comments (9) | TrackBack
Rendering AutoCAD models offscreen using .NET
This question came up in an internal discussion, and I thought I'd share the code provided by our Engineering team with you (with a few minor additions from my side, of course).
The idea is to render a 3D scene off-screen (i.e. save to file the rendered image not visible in the editor). In the below code, we do zoom to the extents of the 3D model that gets created, just to show it's there, but the rendering activity itself is not performed by the 3D view that is used to generate the graphics for AutoCAD's editor window.
A 3D model does need to be loaded in the editor for this to work, so I decided to add a simple sphere to the modelspace and set its material to one that renders nicely (Sitework.Paving - Surfacing.Riverstone.Mortared). The code doesn't import the material programmatically, so you'll want to make sure it's there in the drawing to get the full effect of the rendering (by dragging the material into the drawing view from the materials tool palette, for instance), or to change the code to point to one that exists in the active drawing.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.GraphicsSystem;
using Autodesk.AutoCAD.Interop;
using System.Drawing;
namespace OffscreenRendering
{
public class Commands
{
[CommandMethod("OSR")]
static public void OffscreenRender()
{
CreateSphere();
RenderToFile("c:\\sphere.png");
}
static public void CreateSphere()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
Transaction tr =
doc.TransactionManager.StartTransaction();
using (tr)
{
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
Solid3d sol = new Solid3d();
sol.CreateSphere(10.0);
const string matname =
"Sitework.Paving - Surfacing.Riverstone.Mortared";
DBDictionary matdict =
(DBDictionary)tr.GetObject(
db.MaterialDictionaryId,
OpenMode.ForRead
);
if (matdict.Contains(matname))
{
sol.Material = matname;
}
else
{
ed.WriteMessage(
"\nMaterial (" + matname + ") not found" +
" - sphere will be rendered without it.",
matname
);
}
btr.AppendEntity(sol);
tr.AddNewlyCreatedDBObject(sol, true);
tr.Commit();
}
AcadApplication acadApp =
(AcadApplication)Application.AcadApplication;
acadApp.ZoomExtents();
}
static public void RenderToFile(string filename)
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
int vpn =
System.Convert.ToInt32(
Application.GetSystemVariable("CVPORT")
);
View gsv =
doc.GraphicsManager.GetGsView(vpn, true);
using (View view = gsv.Clone(true, true))
{
Device dev =
doc.GraphicsManager.CreateAutoCADOffScreenDevice();
using (dev)
{
dev.OnSize(doc.GraphicsManager.DisplaySize);
dev.DeviceRenderType = RendererType.FullRender;
dev.Add(view);
using (Bitmap bitmap = view.RenderToImage())
{
bitmap.Save(filename);
ed.WriteMessage(
"\nRendered image saved to: " +
filename
);
}
}
}
}
}
}
And here's the resized contents of the file created at c:\sphere.png by the OSR command:
April 5, 2007 in AutoCAD, AutoCAD .NET, Graphics system | Permalink | Comments (8) | TrackBack

Atom








