Тема: Автоматизация печати в pdf AutoCAD C#

День добрый!

Словил интереснейший баг в процессе написания автоматизатора печати для AutoCad.
Идея такая - на чертеже на разных листах раскиданы динамические блоки - ГОСТовские рамки чертежа. Надо всё, что внутри рамочек, вывести постранично в PDF. Когда решал, как делать, показалось логичным распечатать каждую рамку, используя встроенный принтер "DWG To PDF.pc3". Тут-то и начались проблемы.

Беда в том, чертёж, на котором я тестирую, содержит три листа и суммарно 24 рамки на них. А получившаяся PDFка - три страницы, на каждой из которых выведен только один последний блок с каждого из листов. Никак не могу понять, что именно я делаю не так. Факт в том, что находит он все 24 рамки.

При создании кода пользовался примерами отсюда - http://through-the-interface.typepad.co … /plotting/

Буду благодарен любому совету/помощи. Идеи, в чём беда, у меня закончились =(

Вот код:
<code>using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Internal.Reactors;
using Autodesk.AutoCAD.PlottingServices;
using Autodesk.AutoCAD.Runtime;
using ACAD = Autodesk.AutoCAD.ApplicationServices.Application;
using ED = Autodesk.AutoCAD.EditorInput.Editor;
using ACADExtension;

namespace Plot2PDF
{
    public class Program : IExtensionApplication
    {
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]

        static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);
        List<string> msgs = new List<string>();

        public class GostBlk
        {
            public BlockReference BlockRef;
            public Layout LayoutRef;
        }

        public void Terminate()
        {
            ApplicationEventManager cadWinEvnts = Autodesk.AutoCAD.Internal.Reactors.ApplicationEventManager.Instance();
            //Form.Close();
            msgs.Sort();
            ED ed = ACAD.DocumentManager.MdiActiveDocument.Editor;
            foreach (string msg in msgs)
            {
                ed.WriteMessage(msg);
            }
        }

        public void Initialize()
        {

        }

        static void GetGostStampCollection(Database db, Editor ed, Transaction tr, ref List<GostBlk> GostCol, ref List<Layout> LayList)
        {
            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)
                {
                    Layout lo = (Layout)tr.GetObject(btr.LayoutId, OpenMode.ForRead);
                    if (!LayList.Contains(lo)) LayList.Add(lo);
                    BlockTableRecord ms = (BlockTableRecord)tr.GetObject(lo.BlockTableRecordId, OpenMode.ForRead);
                    foreach (ObjectId objId in ms)
                    {
                        Entity ent = (Entity)tr.GetObject(objId, OpenMode.ForRead);
                        if (!ent.GetType().ToString().Contains("BlockReference")) continue;
                        BlockReference blk = (BlockReference)ent;
                        string Effn = ACADExtension.ACADExt.EffectiveName(blk);
                        if (!Effn.ToUpper().Contains("SHEETGOST")) continue;
                        GostBlk theBlk = new GostBlk();
                        theBlk.BlockRef = blk;
                        theBlk.LayoutRef = lo;
                        GostCol.Add(theBlk);
                    }
                }
            }
        }
       
        [CommandMethod("PlotToPdf")]
        static public void MultiSheetPlot()
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            Transaction tr = db.TransactionManager.StartTransaction();
            using (tr)
            {
                List<GostBlk> BlocksToPlot = new List<GostBlk>();
                List<Layout> LayList = new List<Layout>();
                GetGostStampCollection(db, ed, tr, ref BlocksToPlot, ref LayList);
                ed.WriteMessage("\nThe number of GOST stamps found: " + BlocksToPlot.Count + "\n\n");
                if (BlocksToPlot.Count < 1) return;

                if (PlotFactory.ProcessPlotState == ProcessPlotState.NotPlotting)
                {
                    PlotEngine pe = PlotFactory.CreatePublishEngine();
                    using (pe)
                    {
                        PlotProgressDialog ppd = new PlotProgressDialog(false, BlocksToPlot.Count, true);
                        using (ppd)
                        {
                            int 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;
                            ppd.OnBeginPlot();
                            ppd.IsVisible = true;

                            pe.BeginPlot(ppd, null);
                           
                            foreach (GostBlk gblk in BlocksToPlot)
                            {
                                ppd.StatusMsgString = "Plotting block " + numSheet.ToString() + " of " + BlocksToPlot.Count.ToString();
                                ppd.OnBeginSheet();
                                ppd.LowerSheetProgressRange = 0;
                                ppd.UpperSheetProgressRange = 100;
                                ppd.SheetProgressPos = 0;

                                PlotInfoValidator piv = new PlotInfoValidator();
                                piv.MediaMatchingPolicy = MatchingPolicy.MatchEnabled;

                                PlotPageInfo ppi = new PlotPageInfo();
                                PlotInfo pi = new PlotInfo();
                               
                                BlockReference blk = gblk.BlockRef;
                                Layout lo = gblk.LayoutRef;                                                               
                                Extents3d ext = (Extents3d)blk.Bounds;
                                Point3d first = ext.MaxPoint;
                                Point3d second = ext.MinPoint;

                                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 };
                                acedTrans(first.ToArray(), rbFrom.UnmanagedObject, rbTo.UnmanagedObject, 0, firres);
                                acedTrans(second.ToArray(), rbFrom.UnmanagedObject, rbTo.UnmanagedObject, 0, secres);
                                Extents2d window = new Extents2d(firres[0], firres[1], secres[0], secres[1]);

                                // We need a PlotSettings object based on the layout settings which we then customize
                                PlotSettings ps = new PlotSettings(lo.ModelType);
                                LayoutManager.Current.CurrentLayout = lo.LayoutName;
                                pi.Layout = lo.Id;
                                ps.CopyFrom(lo);

                                // The PlotSettingsValidator helps create a valid PlotSettings object
                                PlotSettingsValidator psv = PlotSettingsValidator.Current;
                                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); //StdScaleType.StdScale1To1
                                psv.SetPlotConfigurationName(ps, "DWG To PDF.pc3", "ISO_A3_(297.00_x_420.00_MM)");
                               
                                pi.OverrideSettings = ps;
                                piv.Validate(pi);

                                if (numSheet == 1)
                                {
                                    pe.BeginDocument(pi, doc.Name, null, 1, true, "c:\\multiblock");
                                }
                               
                                pe.BeginPage(ppi, pi, (numSheet == BlocksToPlot.Count), null);
                                pe.BeginGenerateGraphics(null);
                                ppd.SheetProgressPos = 50;
                                pe.EndGenerateGraphics(null);

                                // Finish the sheet
                                pe.EndPage(null);
                                ppd.SheetProgressPos = 100;
                                ppd.PlotProgressPos += Convert.ToInt32(100 / BlocksToPlot.Count);
                                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.");
                }
            }
        }
    }
}</code>

Re: Автоматизация печати в pdf AutoCAD C#

Как я понял, ты проблему решил здесь:
http://forums.autodesk.com/t5/NET/Batch … -p/3562450

Хотелось бы посмотреть окончательное решение, если не трудно

[FONT=Arial]~'J'~[/FONT]

Re: Автоматизация печати в pdf AutoCAD C#

Да, решилась, завтра допилю напильничком и выложу, может, кому будет полезно.

Re: Автоматизация печати в pdf AutoCAD C#

Спасибо заранее  :)

[FONT=Arial]~'J'~[/FONT]

Re: Автоматизация печати в pdf AutoCAD C#

Итак, рабочий код (тестировал в Acad2010):

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Internal.Reactors;
using Autodesk.AutoCAD.PlottingServices;
using Autodesk.AutoCAD.Runtime;
using ACAD = Autodesk.AutoCAD.ApplicationServices.Application;
using ED = Autodesk.AutoCAD.EditorInput.Editor;

namespace Plot2PDF
{
    public class Program : IExtensionApplication
    {
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]

        static extern int acedTrans(double[] point, IntPtr fromRb, IntPtr toRb, int disp, double[] result);
        List<string> msgs = new List<string>();

        public class Blk2Plt
        {
            public BlockReference BlockRef;
            public Layout LayoutObj;
        }

        public void Terminate()
        {
            ApplicationEventManager cadWinEvnts = Autodesk.AutoCAD.Internal.Reactors.ApplicationEventManager.Instance();
            msgs.Sort();
            ED ed = ACAD.DocumentManager.MdiActiveDocument.Editor;
            foreach (string msg in msgs)
            {
                ed.WriteMessage(msg);
            }
        }

        public void Initialize()
        {

        }

        static string EffectiveName(BlockReference blkref)
        {
            if (blkref.IsDynamicBlock)
            {
                using (BlockTableRecord obj = (BlockTableRecord)blkref.DynamicBlockTableRecord.GetObject(OpenMode.ForRead))
                    return obj.Name;
            }
            return blkref.Name;
        }

        static void GetBlocksToPlotCollection(Database db, Editor ed, Transaction tr, String BlockName, ref List<Blk2Plt> BlockCol)
        {
            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)
                {
                    Layout lo = (Layout)tr.GetObject(btr.LayoutId, OpenMode.ForRead);
                    BlockTableRecord ms = (BlockTableRecord)tr.GetObject(lo.BlockTableRecordId, OpenMode.ForRead);
                    foreach (ObjectId objId in ms)
                    {
                        Entity ent = (Entity)tr.GetObject(objId, OpenMode.ForRead);
                        if (!ent.GetType().ToString().Contains("BlockReference")) continue;
                        BlockReference blk = (BlockReference)ent;
                        string Effn = EffectiveName(blk);
                        if (!Effn.ToUpper().Contains(BlockName.ToUpper())) continue;
                        Blk2Plt theBlk = new Blk2Plt();
                        theBlk.BlockRef = blk;
                        theBlk.LayoutObj = lo;
                        BlockCol.Add(theBlk);
                    }
                }
            }
        }

        static void PlotBlockColToPDF(String BlockName, String PrinterName, String OutPath, String PaperSize = "ISO_A4_(297.00_x_210.00_MM)")
        {
            Document doc = Application.DocumentManager.MdiActiveDocument;
            Editor ed = doc.Editor;
            Database db = doc.Database;
            Transaction tr = db.TransactionManager.StartTransaction();
            Object SysVarBackPlot = Application.GetSystemVariable("BACKGROUNDPLOT");
            Application.SetSystemVariable("BACKGROUNDPLOT", 0);
            using (tr)
            {
                List<Blk2Plt> BlocksToPlot = new List<Blk2Plt>();

                GetBlocksToPlotCollection(db, ed, tr, BlockName, ref BlocksToPlot);//Getting collection of blocks

                ed.WriteMessage("\nThe number of blocks found: " + BlocksToPlot.Count + "\n\n");
                if (BlocksToPlot.Count < 1) return;

                if (PlotFactory.ProcessPlotState == ProcessPlotState.NotPlotting)
                {
                    PlotEngine pe = PlotFactory.CreatePublishEngine();
                    using (pe)
                    {
                        PlotProgressDialog ppd = new PlotProgressDialog(false, BlocksToPlot.Count, true);
                        using (ppd)
                        {
                            int numSheet = 1;
                            // Setting up the PlotProgress dialog
                            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;
                            ppd.OnBeginPlot();
                            ppd.IsVisible = true;

                            pe.BeginPlot(ppd, null);

                            foreach (Blk2Plt gblk in BlocksToPlot)
                            {
                                // Starting new page
                                ppd.StatusMsgString = "Plotting block " + numSheet.ToString() + " of " + BlocksToPlot.Count.ToString();
                                ppd.OnBeginSheet();
                                ppd.LowerSheetProgressRange = 0;
                                ppd.UpperSheetProgressRange = 100;
                                ppd.SheetProgressPos = 0;

                                PlotInfoValidator piv = new PlotInfoValidator();
                                piv.MediaMatchingPolicy = MatchingPolicy.MatchEnabled;
                                PlotPageInfo ppi = new PlotPageInfo();
                                PlotInfo pi = new PlotInfo();
                                BlockReference blk = gblk.BlockRef;
                                Layout lo = gblk.LayoutObj;

                                // Getting coodinates of window to plot
                                Extents3d ext = (Extents3d)blk.Bounds;
                                Point3d first = ext.MaxPoint;
                                Point3d second = ext.MinPoint;
                                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 };
                                acedTrans(first.ToArray(), rbFrom.UnmanagedObject, rbTo.UnmanagedObject, 0, firres);
                                acedTrans(second.ToArray(), rbFrom.UnmanagedObject, rbTo.UnmanagedObject, 0, secres);
                                Extents2d window = new Extents2d(firres[0], firres[1], secres[0], secres[1]);

                                // We need a PlotSettings object based on the layout settings which we then customize
                                PlotSettings ps = new PlotSettings(lo.ModelType);
                                LayoutManager.Current.CurrentLayout = lo.LayoutName;
                                pi.Layout = lo.Id;
                                ps.CopyFrom(lo);

                                // The PlotSettingsValidator helps create a valid PlotSettings object
                                PlotSettingsValidator psv = PlotSettingsValidator.Current;
                                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);
                                psv.SetPlotConfigurationName(ps, PrinterName, PaperSize);

                                pi.OverrideSettings = ps;
                                piv.Validate(pi);

                                if (numSheet == 1) pe.BeginDocument(pi, doc.Name, null, 1, true, OutPath); // Create document for the first page

                                // Plot the window
                                pe.BeginPage(ppi, pi, (numSheet == BlocksToPlot.Count), null);
                                pe.BeginGenerateGraphics(null);
                                ppd.SheetProgressPos = 50;
                                pe.EndGenerateGraphics(null);

                                // Finish the sheet
                                pe.EndPage(null);
                                ppd.SheetProgressPos = 100;
                                ppd.PlotProgressPos += Convert.ToInt32(100 / BlocksToPlot.Count);
                                ppd.OnEndSheet();
                                numSheet++;
                            }
                            // Finish the document and finish the plot
                            pe.EndDocument(null);
                            ppd.PlotProgressPos = 100;
                            ppd.OnEndPlot();
                            pe.EndPlot(null);
                            ed.WriteMessage("\nPlot completed successfully!\n\n");
                        }
                    }
                }
                else
                {
                    ed.WriteMessage("\nAnother plot is in progress.\n\n");
                }
                tr.Commit();
            }
            Application.SetSystemVariable("BACKGROUNDPLOT", SysVarBackPlot);
        }

        [CommandMethod("PlotToPdf")]
        static public void PlotToPdf()
        {
            String BlockName = "SHEETGOST";
            String PrinterName = "DWG To PDF.pc3";
            String PaperSize = "ISO_A3_(297.00_x_420.00_MM)";
            String OutPath = "c:\\plot2pdf";

            PlotBlockColToPDF(BlockName, PrinterName, OutPath, PaperSize);
        }
    }
}

Re: Автоматизация печати в pdf AutoCAD C#

Спасибо, очень нужная вещь
Regards,

[FONT=Arial]~'J'~[/FONT]

Re: Автоматизация печати в pdf AutoCAD C#

Добрый день, подскажите, пожалуйста, а как этот код вставить в acad?

(изменено: Hwd, 4 февраля 2013г. 11:35:15)

Re: Автоматизация печати в pdf AutoCAD C#

Антон Собинов пишет:

Добрый день, подскажите, пожалуйста, а как этот код вставить в acad?

Никак. Это не AutoLISP\Visual LISP. Код нужно компилировать в dll файл (для каждой версии AutoCAD свой) с помощью сторонней IDE.

Re: Автоматизация печати в pdf AutoCAD C#

Hwd пишет:

Никак. Это не AutoLISP\Visual LISP. Код нужно компилировать в dll файл (для каждой версии AutoCAD свой) с помощью сторонней IDE.

А можно поподробней: что такое IDE, как узнать какая нужна, примеры компиляции?
Если можно ссылку на какую-нибудь статью!

Re: Автоматизация печати в pdf AutoCAD C#

IDE - среда разработки (гугл находит ответ за секунду). Нужна MS Visual Studio. На сегодняшний день самая последняя версия - 2012, но вполне подойдёт и 2010. Примеры и т.п. можно глянуть тут.

Re: Автоматизация печати в pdf AutoCAD C#

Hwd,
спасибо большое за ликбез и оперативность!
Гугл не выдал ссылки на MS Visual Studio ;)

Re: Автоматизация печати в pdf AutoCAD C#

Антон Собинов пишет:

Гугл не выдал ссылки на MS Visual Studio

Странный у тебя гугл.

Re: Автоматизация печати в pdf AutoCAD C#

мне одному кажется странной эта карусель?

  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) 
                { 
                    Layout lo = (Layout)tr.GetObject(btr.LayoutId, OpenMode.ForRead); 
                    BlockTableRecord ms = (BlockTableRecord)tr.GetObject(lo.BlockTableRecordId, OpenMode.ForRead); 
                    foreach (ObjectId objId in ms)