Previewing and plotting a single sheet in AutoCAD using .NET

This week's posts take the code I threw together last week for single-sheet and multi-sheet plotting, and introduces the concept of "plot preview".

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

{

  public class PreviewCommands

  {

    [CommandMethod("simprev")]

    static public void 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."

        );

      }

    }

    static PreviewEndPlotStatus 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 = new PlotInfo();

        pi.Layout = btr.LayoutId;

        // We need a PlotSettings object

        // based on the layout settings

        // which we then customize

        PlotSettings ps =

          new PlotSettings(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 =

          new PlotInfoValidator();

        piv.MediaMatchingPolicy =

          MatchingPolicy.MatchEnabled;

        piv.Validate(pi);

        // Create a Progress Dialog to provide info

        // and allow thej user to cancel

        PlotProgressDialog ppd =

          new PlotProgressDialog(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 = new PlotPageInfo();

          pe.BeginPage(

            ppi,

            pi,

            true,

            null

          );

          pe.BeginGenerateGraphics(null);

          ppd.SheetProgressPos = 50;

          pe.EndGenerateGraphics(null);

          // Finish the sheet

          PreviewEndPlotInfo pepi =

            new PreviewEndPlotInfo();

          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.

9 responses to “Previewing and plotting a single sheet in AutoCAD using .NET”

  1. first, thank you for posting to this blog. I have learned a lot from you and this site.

    I copied the above code to a fresh project but wanted to plot to the StyleSheet "monochrome.ctb." however, I get the below error. am I missing something?

    I place the below code between the
    SetStdScaleType and SetPlotCentered lines.

    psv.SetCurrentStyleSheet(ps, "monochrome.ctb");

    --------
    System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Autodesk.AutoCAD.Runtime.Exception: eInvalidInput
    at Autodesk.AutoCAD.DatabaseServices.PlotSettingsValidator.SetCurrentStyleSheet(PlotSettings plotSet, String styleSheetName)
    at ClassLibrary.PreviewCommands.PlotOrPreview

  2. I see what you're experiencing... interestingly when I add this call before yours (even if I don't use the results directly), the code works:

    System.Collections.Specialized.StringCollection sc = psv.GetPlotStyleSheetList();

    Regards,

    Kean

  3. Is it possible to plot dwg file without opening it?

  4. It should be using the new Core Console feature.

    Kean

  5. thank for your help !
    I have a issue. :
    - I need to print with scale 1:1
    --> My layout have units mm
    --> + psv.SetPlotPaperUnits(ps, PlotPaperUnit.Millimeters)

    with all this i need to scale the plot with this :
    Dim Scale As CustomScale = New CustomScale(1, 25.4)
    psv.SetCustomPrintScale(ps, Scale)

    --> Why i need to convert inch to mm units ?

    The plot works fine with this scale.
    If in the plot standard windows of acad, i click on preview plot, the windows change the unit to 'pouce'.
    So how i can set to mm for use a scalle 1to1 ?

  6. Hi Artis,

    I'm really far from being a plotting expert: I suggest you post your question via the ADN team or the appropriate online discussion group.

    Regards,

    Kean

  7. Dear my friend,
    I have a important problem with Plotting is that: after preview, I cannot use any Get UserInput function.
    Example: I add the extra lines (see below) to the end of function void SimplePreview(). But it not work 🙁

    ...
    PromptKeywordOptions pko = new PromptKeywordOptions("\nEnter to plot ");
    pko.Keywords.Add("plot");
    pko.Keywords.Add("Skip");
    pko.Keywords.Add("Nopreview");
    pko.Keywords.Add("Exit");
    pko.Keywords.Default = "plot";
    PromptResult pr = ed.GetKeywords(pko);
    ...
    Can anyone explain why and how to get userinput after preview (or plot something)?
    Thank you!

    1. It's a best practice to perform all the UI requests before starting to process them, wherever possible.

      I'm not sure what you're looking to do here, but pausing/interrupting a plot isn't going to be easy. If that's what you want, please post follow-up questions to the AutoCAD .NET forum.

      Kean

      1. AutoLISP just simple Avatar
        AutoLISP just simple

        I want to build a multiple plot app. But each sheet, may be the user need preview it before decide print or not (by the command line only).
        In ObjectARX 2005 2008, the "PREVIEW" command just work fine. But in AutoCAD .net 2016 the command (or preview function) does not work as well. I cannot get UI after preview.
        Thanks for replying. I will ask int AutoCAD .Net forum!

Leave a Reply to AutoLISP just simple Cancel reply

Your email address will not be published. Required fields are marked *