Previewing and plotting a single sheet in AutoCAD using .NET

I'm learning as I go for much of this, so there are structural (although usually not functional) changes being made to the code as it develops. In this instance, for example, I've factored off common functionality needed by both previewing and plotting into a single helper function. This will no doubt evolve further (and change in structure) when I come to apply the principle to multi-sheet plotting later in the week.

Here's the C# code:

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.PlottingServices;

namespace PlottingApplication

{

publicclassPreviewCommands

{

[CommandMethod("simprev")]

staticpublicvoid SimplePreview()

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

Editor ed = doc.Editor;

Database db = doc.Database;

// PlotEngines do the previewing and plotting

if (PlotFactory.ProcessPlotState ==

ProcessPlotState.NotPlotting)

{

// First we preview...

PreviewEndPlotStatus stat;

PlotEngine pre =

PlotFactory.CreatePreviewEngine(

(int)PreviewEngineFlags.Plot

);

using (pre)

{

stat =

PlotOrPreview(

pre,

true,

db.CurrentSpaceId,

""

);

}

if (stat == PreviewEndPlotStatus.Plot)

{

// And if the user asks, we plot...

PlotEngine ple =

PlotFactory.CreatePublishEngine();

stat =

PlotOrPreview(

ple,

false,

db.CurrentSpaceId,

"c:\\previewed-plot"

);

}

}

else

{

ed.WriteMessage(

"\nAnother plot is in progress."

);

}

}

staticPreviewEndPlotStatus PlotOrPreview(

PlotEngine pe,

bool isPreview,

ObjectId spaceId,

string filename)

{

Document doc =

Application.DocumentManager.MdiActiveDocument;

Editor ed = doc.Editor;

Database db = doc.Database;

PreviewEndPlotStatus ret =

PreviewEndPlotStatus.Cancel;

Transaction tr =

db.TransactionManager.StartTransaction();

using (tr)

{

// We'll be plotting the current layout

BlockTableRecord btr =

(BlockTableRecord)tr.GetObject(

spaceId,

OpenMode.ForRead

);

Layout lo =

(Layout)tr.GetObject(

btr.LayoutId,

OpenMode.ForRead

);

// We need a PlotInfo object

// linked to the layout

PlotInfo pi = newPlotInfo();

pi.Layout = btr.LayoutId;

// We need a PlotSettings object

// based on the layout settings

// which we then customize

PlotSettings ps =

newPlotSettings(lo.ModelType);

ps.CopyFrom(lo);

// The PlotSettingsValidator helps

// create a valid PlotSettings object

PlotSettingsValidator psv =

PlotSettingsValidator.Current;

// We'll plot the extents, centered and

// scaled to fit

psv.SetPlotType(

ps,

Autodesk.AutoCAD.DatabaseServices.PlotType.Extents

);

psv.SetUseStandardScale(ps, true);

psv.SetStdScaleType(ps, StdScaleType.ScaleToFit);

psv.SetPlotCentered(ps, true);

// We'll use the standard DWF PC3, as

// for today we're just plotting to file

psv.SetPlotConfigurationName(

ps,

"DWF6 ePlot.pc3",

"ANSI_A_(8.50_x_11.00_Inches)"

);

// We need to link the PlotInfo to the

// PlotSettings and then validate it

pi.OverrideSettings = ps;

PlotInfoValidator piv =

newPlotInfoValidator();

piv.MediaMatchingPolicy =

MatchingPolicy.MatchEnabled;

piv.Validate(pi);

// Create a Progress Dialog to provide info

// and allow thej user to cancel

PlotProgressDialog ppd =

newPlotProgressDialog(isPreview, 1, true);

using (ppd)

{

ppd.set_PlotMsgString(

PlotMessageIndex.DialogTitle,

"Custom Preview Progress"

);

ppd.set_PlotMsgString(

PlotMessageIndex.SheetName,

doc.Name.Substring(

doc.Name.LastIndexOf("\\") + 1

)

);

ppd.set_PlotMsgString(

PlotMessageIndex.CancelJobButtonMessage,

"Cancel Job"

);

ppd.set_PlotMsgString(

PlotMessageIndex.CancelSheetButtonMessage,

"Cancel Sheet"

);

ppd.set_PlotMsgString(

PlotMessageIndex.SheetSetProgressCaption,

"Sheet Set Progress"

);

ppd.set_PlotMsgString(

PlotMessageIndex.SheetProgressCaption,

"Sheet Progress"

);

ppd.LowerPlotProgressRange = 0;

ppd.UpperPlotProgressRange = 100;

ppd.PlotProgressPos = 0;

// Let's start the plot/preview, at last

ppd.OnBeginPlot();

ppd.IsVisible = true;

pe.BeginPlot(ppd, null);

// We'll be plotting/previewing

// a single document

pe.BeginDocument(

pi,

doc.Name,

null,

1,

!isPreview,

filename

);

// Which contains a single sheet

ppd.OnBeginSheet();

ppd.LowerSheetProgressRange = 0;

ppd.UpperSheetProgressRange = 100;

ppd.SheetProgressPos = 0;

PlotPageInfo ppi = newPlotPageInfo();

pe.BeginPage(

ppi,

pi,

true,

null

);

pe.BeginGenerateGraphics(null);

ppd.SheetProgressPos = 50;

pe.EndGenerateGraphics(null);

// Finish the sheet

PreviewEndPlotInfo pepi =

newPreviewEndPlotInfo();

pe.EndPage(pepi);

ret = pepi.Status;

ppd.SheetProgressPos = 100;

ppd.OnEndSheet();

// Finish the document

pe.EndDocument(null);

// And finish the plot

ppd.PlotProgressPos = 100;

ppd.OnEndPlot();

pe.EndPlot(null);

}

// Committing is cheaper than aborting

tr.Commit();

}

return ret;

}

}

}

When you execute the SIMPREV command, you receive enter a "preview" mode, from where you can either cancel or plot. The trick was really in determining the button selected by the user, which we do by passing an appropriate object (of class PreviewEndPlotInfo) into the EndPage() function, to collect information on what the users selects. The next post will take this further, allowing the user to cycle through multiple sheets using "next" and "previous" buttons.