雪山飞狐_lzh 发表于 2009-6-20 16:17:00

Kean专题(12)—Plotting

一、使用Design Review 2008的批打印
May 10, 2007
Automating batch printing of DWF files using Design Review 2008
We sometimes receive questions on how best to automate the printing of DWF files. Autodesk Design Review 2008 now has a new Batch Print Plug-in enabling just this.
Once you've installed the plug-in, you'll be able to use the Batch Print Wizard in Design Review (on the file menu, once a DWF has been loaded). This Wizard allows you to configure a batch job for Design Review to process and save it to a BPJ (Batch Print Job) file. This BPJ (which is basically a very simple XML file) can then be used to drive the batch print process automatically.
The next logical step is clearly to create the BPJ programmatically, which can be done using a number of XML libraries (MS XML etc.) or simply by writing out a text file using your favourite string output routines.
So let's look at creating the BPJ file "manually" using the Batch Print Wizard.
Here's the second screen you'll see, once you've skipped the welcome:


When you've selected the files you wish to print and added them to the right-hand side using the ">" button, you can move on to the next page:


This is where you modify the print setup for each of your DWFs, by clicking on the item and hitting &quotrint Setup", or just double-clicking the item.


And then you're ready to save the BPJ file (or just &quotrint" directly).
I saved mine as "c:\My Documents\MyFiles.bpj", and here are its contents, with additional whitespace added for readability:复制代码This is clearly straightforward to create programmatically from your application. The next question is how best to automate the print process, now we have our BPJ.
The simplest way is to call the Design Review executable with the BPJ file as a command-line argument:


The executable returns straight away, and you'll see a log file created in the same location as the BPJ (in my case "c:\My Documents\MyFiles.log"), detailing the results of the print job:复制代码This log file can be parsed programmatically if it's important for your application to know whether any pages had difficulty printing.
**** Hidden Message *****

雪山飞狐_lzh 发表于 2009-6-21 11:34:00

二、使用NetApi实现简单的打印任务
September 25, 2007
Driving a basic AutoCAD plot using .NET
I just missed my connecting flight in Chicago, so have 3 hours to pass until the next, and decided to post some code I finally got around to writing on the plane from Zurich.
I've had a few requests for code showing how to plot using the .NET API in AutoCAD. There's an existing ObjectARX (C++) sample on the SDK, under samples/editor/AsdkPlotAPI, but there isn't a publicly posted .NET version right now.
Here's the C# code I put together. Please bear in mind that it was written during less than ideal coding conditions, and I haven't spent a substantial amount of time going through it... it seems to work fine for me, but do post a comment if you have trouble with it.
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.PlottingServices;
namespace PlottingApplication
{
public class PlottingCommands
{
   
    static public void SimplePlot()
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      Database db = doc.Database;
      Transaction tr =
      db.TransactionManager.StartTransaction();
      using (tr)
      {
      // We'll be plotting the current layout
      BlockTableRecord btr =
          (BlockTableRecord)tr.GetObject(
            db.CurrentSpaceId,
            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);
      // A PlotEngine does the actual plotting
      // (can also create one for Preview)
      if (PlotFactory.ProcessPlotState ==
            ProcessPlotState.NotPlotting)
      {
          PlotEngine pe =
            PlotFactory.CreatePublishEngine();
          using (pe)
          {
            // Create a Progress Dialog to provide info
            // and allow thej user to cancel
            PlotProgressDialog ppd =
            new PlotProgressDialog(false, 1, true);
            using (ppd)
            {
            ppd.set_PlotMsgString(
                PlotMessageIndex.DialogTitle,
                "Custom Plot Progress"
            );
            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, at last
            ppd.OnBeginPlot();
            ppd.IsVisible = true;
            pe.BeginPlot(ppd, null);
            // We'll be plotting a single document
            pe.BeginDocument(
                pi,
                doc.Name,
                null,
                1,
                true, // Let's plot to file
                "c:\\test-output"
            );
            // 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);
            pe.EndGenerateGraphics(null);
            // Finish the sheet
            pe.EndPage(null);
            ppd.SheetProgressPos = 100;
            ppd.OnEndSheet();
            // Finish the document
            pe.EndDocument(null);
            // And finish the plot
            ppd.PlotProgressPos = 100;
            ppd.OnEndPlot();
            pe.EndPlot(null);
            }
          }
      }
      else
      {
          ed.WriteMessage(
            "\nAnother plot is in progress."
          );
      }
      }
    }
}
}A few comments on the code: I chose to plot to a file using the standard DWF plot driver/PC3 file, mainly as it avoids having to second-guess what printers/plotters everyone uses. :-) The SDK sample populates comboboxes in a dialog to allow selection of the device and the media size, but I've just gone with a choice that should work on all systems.
Here's what you should see when you launch the SIMPLOT command:


The output file should be created in "c:\test-output.dwf".
I added a simple check to fail gracefully when another plot is in progress... as this code will drive either a foreground or a background plot (depending on the value of the BACKGROUNDPLOT system variable), there's clear scope for failure if the code doesn't check via PlotFactory.ProcessPlotState (or handle the exception if another plot is already happening when you call PlotFactory.CreatePublishEngine()).
Now that I'm online I've found there's quite a similar code sample to the ADN site (also converted from the original SDK sample, I suspect):

雪山飞狐_lzh 发表于 2009-6-21 11:40:00

三、使用NetApi实现多表打印任务
September 29, 2007
Driving a multi-sheet AutoCAD plot using .NET
Somewhat symmetrically I’m posting this from Chicago airport, once again, but thankfully I’m now on my way home. It was a busy week of meetings, but I did get the chance to put together some code that extended the last post into the realm of multi-sheet plot jobs.
The following code took some work, but I finally managed to iron out the obvious wrinkles and put together an approach to plot multiple sheets into a single document. The standard DWF6 driver doesn’t appear to support multiple sheet jobs (directly, at least), so I chose to use the DWFx driver that I probably downloaded and installed from here.
I haven’t “diffed” and colour-coded the changed lines with the previous post, as there ended up being quite a lot of swapping around etc., but you should be able to perform that comparison yourself, if you so wish.
Here’s the C# code:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.PlottingServices;
namespace PlottingApplication
{
public class PlottingCommands
{
   
    static public void MultiSheetPlot()
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      Database db = doc.Database;
      Transaction tr =
      db.TransactionManager.StartTransaction();
      using (tr)
      {
      BlockTable bt =
          (BlockTable)tr.GetObject(
            db.BlockTableId,
            OpenMode.ForRead
          );
      PlotInfo pi = new PlotInfo();
      PlotInfoValidator piv =
          new PlotInfoValidator();
      piv.MediaMatchingPolicy =
          MatchingPolicy.MatchEnabled;
      // A PlotEngine does the actual plotting
      // (can also create one for Preview)
      if (PlotFactory.ProcessPlotState ==
            ProcessPlotState.NotPlotting)
      {
          PlotEngine pe =
            PlotFactory.CreatePublishEngine();
          using (pe)
          {
            // Create a Progress Dialog to provide info
            // and allow thej user to cancel
            PlotProgressDialog ppd =
            new PlotProgressDialog(false, 1, true);
            using (ppd)
            {
            ObjectIdCollection layoutsToPlot =
                new ObjectIdCollection();
            foreach (ObjectId btrId in bt)
            {
                BlockTableRecord btr =
                  (BlockTableRecord)tr.GetObject(
                  btrId,
                  OpenMode.ForRead
                  );
                if (btr.IsLayout &&
                  btr.Name.ToUpper() !=
                      BlockTableRecord.ModelSpace.ToUpper())
                {
                  layoutsToPlot.Add(btrId);
                }
            }
            int numSheet = 1;
            foreach (ObjectId btrId in layoutsToPlot)
            {
                BlockTableRecord btr =
                  (BlockTableRecord)tr.GetObject(
                  btrId,
                  OpenMode.ForRead
                  );
                Layout lo =
                  (Layout)tr.GetObject(
                  btr.LayoutId,
                  OpenMode.ForRead
                  );
                // 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 DWFx PC3, as
                // this supports multiple sheets
                psv.SetPlotConfigurationName(
                  ps,
                  "DWFx ePlot (XPS Compatible).pc3",
                  "ANSI_A_(8.50_x_11.00_Inches)"
                );
                // We need a PlotInfo object
                // linked to the layout
                pi.Layout = btr.LayoutId;
                // Make the layout we're plotting current
                LayoutManager.Current.CurrentLayout =
                  lo.LayoutName;
                // We need to link the PlotInfo to the
                // PlotSettings and then validate it
                pi.OverrideSettings = ps;
                piv.Validate(pi);
                if (numSheet == 1)
                {
                  ppd.set_PlotMsgString(
                  PlotMessageIndex.DialogTitle,
                  "Custom Plot Progress"
                  );
                  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, at last
                  ppd.OnBeginPlot();
                  ppd.IsVisible = true;
                  pe.BeginPlot(ppd, null);
                  // We'll be plotting a single document
                  pe.BeginDocument(
                  pi,
                  doc.Name,
                  null,
                  1,
                  true, // Let's plot to file
                  "c:\\test-multi-sheet"
                  );
                }
                // Which may contain multiple sheets
                ppd.StatusMsgString =
                  "Plotting " +
                  doc.Name.Substring(
                  doc.Name.LastIndexOf("\") + 1
                  ) +
                  " - sheet " + numSheet.ToString() +
                  " of " + layoutsToPlot.Count.ToString();
                ppd.OnBeginSheet();
                ppd.LowerSheetProgressRange = 0;
                ppd.UpperSheetProgressRange = 100;
                ppd.SheetProgressPos = 0;
                PlotPageInfo ppi = new PlotPageInfo();
                pe.BeginPage(
                  ppi,
                  pi,
                  (numSheet == layoutsToPlot.Count),
                  null
                );
                pe.BeginGenerateGraphics(null);
                ppd.SheetProgressPos = 50;
                pe.EndGenerateGraphics(null);
                // Finish the sheet
                pe.EndPage(null);
                ppd.SheetProgressPos = 100;
                ppd.OnEndSheet();
                numSheet++;
            }
            // Finish the document
            pe.EndDocument(null);
            // And finish the plot
            ppd.PlotProgressPos = 100;
            ppd.OnEndPlot();
            pe.EndPlot(null);
            }
          }
      }
      else
      {
          ed.WriteMessage(
            "\nAnother plot is in progress."
          );
      }
      }
    }
}
}The output of the MPLOT command will be created in “c:\test-multi-sheet.dwfx”, which can then be viewed using Autodesk Design Review 2008 or the XPS viewer that ships with Windows Vista or from here for Windows XP.
Update
I spent some more time looking at this code and noticed a minor issue... We need to tell the plot dialog that we're working with multiple sheets in its constructor. So we first need to count the sheets and then create the dialog. Here's the modified section of code:
          PlotEngine pe =
            PlotFactory.CreatePublishEngine();
          using (pe)
          {
            // Collect all the paperspace layouts
            // for plotting
            ObjectIdCollection layoutsToPlot =
            new ObjectIdCollection();
            foreach (ObjectId btrId in bt)
            {
            BlockTableRecord btr =
                (BlockTableRecord)tr.GetObject(
                  btrId,
                  OpenMode.ForRead
                );
            if (btr.IsLayout &&
                  btr.Name.ToUpper() !=
                  BlockTableRecord.ModelSpace.ToUpper())
            {
                layoutsToPlot.Add(btrId);
            }
            }
            // Create a Progress Dialog to provide info
            // and allow thej user to cancel
            PlotProgressDialog ppd =
            new PlotProgressDialog(
                false,
                layoutsToPlot.Count,
                true
            );
            using (ppd)
            {This now leads to the plot progress dialog showing multiple progress bars:

雪山飞狐_lzh 发表于 2009-6-23 22:04:00

四、单表打印预览
October 01, 2007
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
{
   
    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.

雪山飞狐_lzh 发表于 2009-6-23 22:07:00

五、多表打印预览
October 04, 2007
Previewing and plotting multiple sheets in AutoCAD using .NET
This was a fun one to work on. The code in this post combines and extends upon techniques shown in two earlier posts: one showing how to plot multiple sheets and the other showing how to preview a single-sheet plot.
One of the key differences when plotting or previewing is that while plotting can directly support multiple sheets (assuming the device does so), previewing does not. The good news is that AutoCAD provides you the user interface elements to allow cycling through plots: the user is provided with "Next" and &quotrevious" buttons - it's then up to you to implement the appropriate logic to preview different sheets when the buttons are used.
I chose to use the same helper function for both preview and plot, even though they are a little different in nature. The reason is obvious (to me, at least) - it reduces the amount of code to debug and maintain - but it might, for some, make the code a little less easy to read. Ultimately the trick I used was to reduce the set of sheets being handled at the beginning of the function to a single sheet in the case of a preview, which allowed me to combine both approaches in a single function.
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;
using System.Collections.Generic;
namespace PlottingApplication
{
public class PreviewCommands
{
   
    static public void MultiSheetPreview()
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      Database db = doc.Database;
      ObjectIdCollection layoutsToPlot =
      new ObjectIdCollection();
      Transaction tr =
      db.TransactionManager.StartTransaction();
      using (tr)
      {
      // First we need to collect the layouts to
      // plot/preview in tab order
      SortedDictionary layoutDict =
          new SortedDictionary();
      BlockTable bt =
          (BlockTable)tr.GetObject(
            db.BlockTableId,
            OpenMode.ForRead
          );
      foreach (ObjectId btrId in bt)
      {
          BlockTableRecord btr =
            (BlockTableRecord)tr.GetObject(
            btrId,
            OpenMode.ForRead
            );
          if (btr.IsLayout &&
            btr.Name.ToUpper() !=
                BlockTableRecord.ModelSpace.ToUpper())
          {
            // The dictionary we're using will
            // sort on the tab order of the layout
            Layout lo =
            (Layout)tr.GetObject(
                btr.LayoutId,
                OpenMode.ForRead
            );
            layoutDict.Add(lo.TabOrder,btrId);
          }
      }
      // Let's now get the layout IDs and add them to a
      // standard ObjectIdCollection
      SortedDictionary.ValueCollection vc =
          layoutDict.Values;
      foreach (ObjectId id in vc)
      {
          layoutsToPlot.Add(id);
      }
      // Committing is cheaper than aborting
      tr.Commit();
      }
      // PlotEngines do the previewing and plotting
      if (PlotFactory.ProcessPlotState ==
          ProcessPlotState.NotPlotting)
      {
      int layoutNum = 0;
      bool isFinished = false;
      bool isReadyForPlot = false;
      while (!isFinished)
      {
          // Create the preview engine with the appropriate
          // buttons enabled - this depends on which
          // layout in the list is being previewed
          PreviewEngineFlags flags =
            PreviewEngineFlags.Plot;
          if (layoutNum > 0)
            flags |= PreviewEngineFlags.PreviousSheet;
          if (layoutNum = 0)
      {
      // Preview is really pre-sheet, so we reduce the
      // sheet collection to contain the one we want
      layoutsToPlot = new ObjectIdCollection();
      layoutsToPlot.Add(
          layoutSet
      );
      }
      else
      {
      // If we're plotting we need all the sheets,
      // so copy the ObjectIds across
      ObjectId[] ids = new ObjectId;
      layoutSet.CopyTo(ids,0);
      layoutsToPlot = new ObjectIdCollection(ids);
      }
      Transaction tr =
      db.TransactionManager.StartTransaction();
      using (tr)
      {
      // Create a Progress Dialog to provide info
      // and allow thej user to cancel
      PlotProgressDialog ppd =
          new PlotProgressDialog(
            isPreview,
            layoutsToPlot.Count,
            true
          );
      using (ppd)
      {
          int numSheet = 1;
          foreach (ObjectId btrId in layoutsToPlot)
          {
            BlockTableRecord btr =
            (BlockTableRecord)tr.GetObject(
                btrId,
                OpenMode.ForRead
            );
            Layout lo =
            (Layout)tr.GetObject(
                btr.LayoutId,
                OpenMode.ForRead
            );
            // 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 DWFx PC3, as
            // this supports multiple sheets
            psv.SetPlotConfigurationName(
            ps,
            "DWFx ePlot (XPS Compatible).pc3",
            "ANSI_A_(8.50_x_11.00_Inches)"
            );
            // We need a PlotInfo object
            // linked to the layout
            PlotInfo pi = new PlotInfo();
            pi.Layout = btr.LayoutId;
            // Make the layout we're plotting current
            LayoutManager.Current.CurrentLayout =
            lo.LayoutName;
            // 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);
            // We set the sheet name per sheet
            ppd.set_PlotMsgString(
            PlotMessageIndex.SheetName,
            doc.Name.Substring(
                doc.Name.LastIndexOf("\") + 1
            ) +
            " - " +
            lo.LayoutName
            );
            if (numSheet == 1)
            {
            // All other messages get set once
            ppd.set_PlotMsgString(
                PlotMessageIndex.DialogTitle,
                "Custom Preview Progress"
            );
            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 a single document
            pe.BeginDocument(
                pi,
                doc.Name,
                null,
                1,
                !isPreview,
                filename
            );
            }
            // Which may contains multiple sheets
            ppd.LowerSheetProgressRange = 0;
            ppd.UpperSheetProgressRange = 100;
            ppd.SheetProgressPos = 0;
            PlotPageInfo ppi = new PlotPageInfo();
            pe.BeginPage(
            ppi,
            pi,
            (numSheet == layoutsToPlot.Count),
            null
            );
            ppd.OnBeginSheet();
            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();
            numSheet++;
            // Update the overall progress
            ppd.PlotProgressPos +=
            (100 / layoutsToPlot.Count);
          }
          // Finish the document
          pe.EndDocument(null);
          // And finish the plot
          ppd.PlotProgressPos = 100;
          ppd.OnEndPlot();
          pe.EndPlot(null);
      }
      }
      return ret;
    }
}
}Here's what you see when you run the MPREV command:


Once you select the plot button, the plot gets driven as before:


雪山飞狐_lzh 发表于 2009-7-1 17:24:00

六、选择打印设备和打印介质
October 09, 2007
Allowing selection of an AutoCAD plot device and media name using .NET
A comment came in on this previous post regarding how best to know whether a media name is valid during your plot configuration.
There are a few approaches, other than the one I chose of hardcoding the device and media names. The first is to implement a user interface of some kind which allows the user to select the device and media names. Another approach for setting the media name is to use PlotSettingsValidator.SetClosestMediaName() to choose the media name that most closely matches the paper size you desire.
Today I'll focus on the first option, although I'm only going to implement a basic, command-line user interface. It should be straightforward to extend this to implement a WinForm with comboboxes for the device and media names.
I implemented a simple function called ChooseDeviceAndMedia() which queries the current device list, allows selection from it, and then gets the media name list and allows selection from that. I chose not to worry about displaying locale-specific names, for now - I'll leave that for a future post (let me know if you're interested :-).
Here's the function integrated into the C# code from this previous post, which defines a command called MPLOT:
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.PlottingServices;
using System.Collections.Specialized;
namespace PlottingApplication
{
public class PlottingCommands
{
    static public string[] ChooseDeviceAndMedia()
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      // Assign default return values
      string devname = "", medname = "";
      PlotSettingsValidator psv =
      PlotSettingsValidator.Current;
      // Let's first select the device
      StringCollection devlist =
      psv.GetPlotDeviceList();
      for (int i = 0; i 复制代码

雪山飞狐_lzh 发表于 2009-7-1 17:29:00

七、窗选打印
October 11, 2007
Plotting a window from AutoCAD using .NET
This post extends this previous post that dealt with driving a single-sheet AutoCAD plot by adding some code to handle selection and transformation of a window to plot.
First order of business was to allow the user to select the window to plot. For this I used the classic combination of Editor.GetPoint() for the first corner) and Editor.GetCorner() for the second. All well and good, but the points returned by these functions are in UCS (User Coordinate System) coordinates. Which meant that as it stood, the code would work just fine if (and only if) the view we were using to select the window was parallell with the World Coordinate System (and no additional UCS was in place). In order to deal with the very common scenario of either a UCS being used or the current modelspace view being orbited (etc.), we need to transform the current UCS coordinates into DCS, the Display Coordinate System.
Thankfully that's pretty easy: no need for matrices or anything, we simply use another old friend, acedTrans() (the ObjectARX equivalent of the (trans) function, for you LISPers out there). There isn't a direct equivalent for this function in the managed API (that I'm aware of), so we have to use P/Invoke to call the ObjectARX function. The technique is shown in this DevNote, for those of you that have access to the ADN website:
How to call acedTrans from .NET application?
Otherwise the changes to the original code are very minor: we need to set the extents of the window to plot and then set the plot type to "window", apparently in that order. AutoCAD complained when I initially made the calls in the opposite sequence.
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;
using Autodesk.AutoCAD.Geometry;
using System.Runtime.InteropServices;
using System;
namespace PlottingApplication
{
public class SimplePlottingCommands
{
    [DllImport("acad.exe",
            CallingConvention = CallingConvention.Cdecl,
            EntryPoint="acedTrans")
    ]
    static extern int acedTrans(
      double[] point,
      IntPtr fromRb,
      IntPtr toRb,
      int disp,
      double[] result
    );
   
    static public void WindowPlot()
    {
      Document doc =
      Application.DocumentManager.MdiActiveDocument;
      Editor ed = doc.Editor;
      Database db = doc.Database;
      PromptPointOptions ppo =
      new PromptPointOptions(
          "\nSelect first corner of plot area: "
      );
      ppo.AllowNone = false;
      PromptPointResult ppr =
      ed.GetPoint(ppo);
      if (ppr.Status != PromptStatus.OK)
      return;
      Point3d first = ppr.Value;
      PromptCornerOptions pco =
      new PromptCornerOptions(
          "\nSelect second corner of plot area: ",
          first
      );
      ppr = ed.GetCorner(pco);
      if (ppr.Status != PromptStatus.OK)
      return;
      Point3d second = ppr.Value;
      // Transform from UCS to DCS
      ResultBuffer rbFrom =
      new ResultBuffer(new TypedValue(5003, 1)),
                  rbTo =
      new ResultBuffer(new TypedValue(5003, 2));
      double[] firres = new double[] { 0, 0, 0 };
      double[] secres = new double[] { 0, 0, 0 };
      // Transform the first point...
      acedTrans(
      first.ToArray(),
      rbFrom.UnmanagedObject,
      rbTo.UnmanagedObject,
      0,
      firres
      );
      // ... and the second
      acedTrans(
      second.ToArray(),
      rbFrom.UnmanagedObject,
      rbTo.UnmanagedObject,
      0,
      secres
      );
      // We can safely drop the Z-coord at this stage
      Extents2d window =
      new Extents2d(
          firres,
          firres,
          secres,
          secres
      );
      Transaction tr =
      db.TransactionManager.StartTransaction();
      using (tr)
      {
      // We'll be plotting the current layout
      BlockTableRecord btr =
          (BlockTableRecord)tr.GetObject(
            db.CurrentSpaceId,
            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.SetPlotWindowArea(ps, window);
      psv.SetPlotType(
          ps,
      Autodesk.AutoCAD.DatabaseServices.PlotType.Window
      );
      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);
      // A PlotEngine does the actual plotting
      // (can also create one for Preview)
      if (PlotFactory.ProcessPlotState ==
            ProcessPlotState.NotPlotting)
      {
          PlotEngine pe =
            PlotFactory.CreatePublishEngine();
          using (pe)
          {
            // Create a Progress Dialog to provide info
            // and allow thej user to cancel
            PlotProgressDialog ppd =
            new PlotProgressDialog(false, 1, true);
            using (ppd)
            {
            ppd.set_PlotMsgString(
                PlotMessageIndex.DialogTitle,
                "Custom Plot Progress"
            );
            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, at last
            ppd.OnBeginPlot();
            ppd.IsVisible = true;
            pe.BeginPlot(ppd, null);
            // We'll be plotting a single document
            pe.BeginDocument(
                pi,
                doc.Name,
                null,
                1,
                true, // Let's plot to file
                "c:\\test-output"
            );
            // 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);
            pe.EndGenerateGraphics(null);
            // Finish the sheet
            pe.EndPage(null);
            ppd.SheetProgressPos = 100;
            ppd.OnEndSheet();
            // Finish the document
            pe.EndDocument(null);
            // And finish the plot
            ppd.PlotProgressPos = 100;
            ppd.OnEndPlot();
            pe.EndPlot(null);
            }
          }
      }
      else
      {
          ed.WriteMessage(
            "\nAnother plot is in progress."
          );
      }
      }
    }
}
}

trample 发表于 2015-12-9 23:41:00

有翻译过来的么,看着眼晕

menethil 发表于 2017-12-2 14:20:00

有自定义图幅的方法吗?

azbd 发表于 2019-1-23 09:24:00

打印预览有没有调过了的?为啥一直卡在预览界面?
页: [1]
查看完整版本: Kean专题(12)—Plotting