Нюансы использования acedTrans

Автор Тема: Нюансы использования acedTrans  (Прочитано 5419 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Особенности вызова функции acedTrans не ограничиваются тем, что она может находиться либо в accore.dll, либо в acad.exe, в зависимости от версии AutoCAD. Эта функция может иметь ещё и разные имена, причём в рамках одной и той же версии AutoCAD - для каждой платформы (x86, x64) свой вариант имени. Этот момент продемонстрирован ниже в коде.
Код - C# [Выбрать]
  1. // ============================================================================
  2. // PlotRegionToPDF.cs
  3. // © Andrey Bushman, 2014
  4. // ============================================================================
  5. // The PLOTREGION command plot a Region object to PDF.
  6. // ============================================================================
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Linq;
  10. using System.Text;
  11. using System.Runtime.InteropServices;
  12.  
  13. using cad = Autodesk.AutoCAD.ApplicationServices.Application;
  14. using Ap = Autodesk.AutoCAD.ApplicationServices;
  15. using Db = Autodesk.AutoCAD.DatabaseServices;
  16. using Ed = Autodesk.AutoCAD.EditorInput;
  17. using Rt = Autodesk.AutoCAD.Runtime;
  18. using Gm = Autodesk.AutoCAD.Geometry;
  19. using Wn = Autodesk.AutoCAD.Windows;
  20. using Hs = Autodesk.AutoCAD.DatabaseServices.HostApplicationServices;
  21. using Us = Autodesk.AutoCAD.DatabaseServices.SymbolUtilityServices;
  22. using Br = Autodesk.AutoCAD.BoundaryRepresentation;
  23. using Pt = Autodesk.AutoCAD.PlottingServices;
  24.  
  25. [assembly: Rt.CommandClass(typeof(Bushman.CAD.ProblemSamples.PlotRegionToPDF))]
  26.  
  27. namespace Bushman.CAD.ProblemSamples {
  28.  
  29.   public static class PlotRegionToPDF {
  30. #if AUTOCAD_NEWER_THAN_2012
  31.     const String acedTransOwner = "accore.dll";
  32. #else
  33.     const String acedTransOwner = "acad.exe";    
  34. #endif
  35.  
  36. #if AUTOCAD_NEWER_THAN_2014
  37.     const String acedTrans_x86_Prefix = "_";
  38. #else
  39.     const String acedTrans_x86_Prefix = "";
  40. #endif
  41.  
  42.     const String acedTransName = "acedTrans";
  43.  
  44.     [DllImport(acedTransOwner, CallingConvention = CallingConvention.Cdecl,
  45.             EntryPoint = acedTrans_x86_Prefix + acedTransName)]
  46.     static extern Int32 acedTrans_x86(Double[] point, IntPtr fromRb,
  47.       IntPtr toRb, Int32 disp, Double[] result);
  48.  
  49.     [DllImport(acedTransOwner, CallingConvention = CallingConvention.Cdecl,
  50.             EntryPoint = acedTransName)]
  51.     static extern Int32 acedTrans_x64(Double[] point, IntPtr fromRb,
  52.       IntPtr toRb, Int32 disp, Double[] result);
  53.  
  54.     public static Int32 acedTrans(Double[] point, IntPtr fromRb, IntPtr toRb,
  55.       Int32 disp, Double[] result) {
  56.         if(IntPtr.Size == 4)
  57.           return acedTrans_x86(point, fromRb, toRb, disp, result);
  58.         else
  59.           return acedTrans_x64(point, fromRb, toRb, disp, result);
  60.     }
  61.  
  62.     [Rt.CommandMethod("plotRegion", Rt.CommandFlags.Modal)]
  63.     public static void PlotRegion() {
  64.       Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  65.       if(doc == null || doc.IsDisposed)
  66.         return;
  67.  
  68.       Ed.Editor ed = doc.Editor;
  69.       Db.Database db = doc.Database;
  70.  
  71.       using(doc.LockDocument()) {
  72.         Ed.PromptEntityOptions peo = new Ed.PromptEntityOptions(
  73.          "\nSelect a region"
  74.          );
  75.  
  76.         peo.SetRejectMessage("\nIt is not a region."
  77.           );
  78.         peo.AddAllowedClass(typeof(Db.Region), false);
  79.  
  80.         Ed.PromptEntityResult per = ed.GetEntity(peo);
  81.  
  82.         if(per.Status != Ed.PromptStatus.OK) {
  83.           ed.WriteMessage("\nCommand canceled.\n");
  84.           return;
  85.         }
  86.  
  87.         Db.ObjectId regionId = per.ObjectId;
  88.  
  89.         Microsoft.Win32.SaveFileDialog saveFileDialog = new Microsoft.Win32
  90.           .SaveFileDialog();
  91.         saveFileDialog.Title =
  92.           "PDF file name";
  93.         saveFileDialog.Filter = "PDF-files|*.pdf";
  94.         bool? result = saveFileDialog.ShowDialog();
  95.  
  96.         if(!result.HasValue || !result.Value) {
  97.           ed.WriteMessage("\nCommand canceled.");
  98.           return;
  99.         }
  100.  
  101.         String pdfFileName = saveFileDialog.FileName;
  102.  
  103.         PlotRegion(regionId, "DWG To PDF.pc3",
  104.           "ISO_A4_(210.00_x_297.00_MM)", pdfFileName);
  105.  
  106.         ed.WriteMessage("\nThe \"{0}\" file created.\n", pdfFileName);
  107.       }
  108.     }
  109.  
  110.     // This method helps to get correct "boundary box" for the regions which
  111.     // created through the splines. Written by Alexander Rivilis.
  112.     public static void GetVisualBoundary(this Db.Region region, double delta,
  113.         ref Gm.Point2d minPoint, ref Gm.Point2d maxPoint) {
  114.       using(Gm.BoundBlock3d boundBlk = new Gm.BoundBlock3d()) {
  115.         using(Br.Brep brep = new Br.Brep(region)) {
  116.           foreach(Br.Edge edge in brep.Edges) {
  117.             using(Gm.Curve3d curve = edge.Curve) {
  118.               Gm.ExternalCurve3d curve3d = curve as Gm.ExternalCurve3d;
  119.  
  120.               if(curve3d != null && curve3d.IsNurbCurve) {
  121.                 using(Gm.NurbCurve3d nurbCurve = curve3d.NativeCurve
  122.                   as Gm.NurbCurve3d) {
  123.                   Gm.Interval interval = nurbCurve.GetInterval();
  124.                   for(double par = interval.LowerBound; par <=
  125.                     interval.UpperBound; par += (delta * 2.0)) {
  126.                     Gm.Point3d p = nurbCurve.EvaluatePoint(par);
  127.                     if(!boundBlk.IsBox)
  128.                       boundBlk.Set(p, p);
  129.                     else
  130.                       boundBlk.Extend(p);
  131.                   }
  132.                 }
  133.               }
  134.               else {
  135.                 if(!boundBlk.IsBox) {
  136.                   boundBlk.Set(edge.BoundBlock.GetMinimumPoint(),
  137.                     edge.BoundBlock.GetMaximumPoint());
  138.                 }
  139.                 else {
  140.                   boundBlk.Extend(edge.BoundBlock.GetMinimumPoint());
  141.                   boundBlk.Extend(edge.BoundBlock.GetMaximumPoint());
  142.                 }
  143.               }
  144.             }
  145.           }
  146.         }
  147.         boundBlk.Swell(delta);
  148.  
  149.         minPoint = new Gm.Point2d(boundBlk.GetMinimumPoint().X,
  150.           boundBlk.GetMinimumPoint().Y);
  151.         maxPoint = new Gm.Point2d(boundBlk.GetMaximumPoint().X,
  152.           boundBlk.GetMaximumPoint().Y);
  153.       }
  154.     }
  155.  
  156.     // This code based on Kean Walmsley's article:
  157.     // http://through-the-interface.typepad.com/through_the_interface/2007/10/plotting-a-wind.html
  158.     public static void PlotRegion(Db.ObjectId regionId, String pcsFileName,
  159.   String mediaName, String outputFileName) {
  160.  
  161.       if(regionId.IsNull)
  162.         throw new ArgumentException("regionId.IsNull == true");
  163.       if(!regionId.IsValid)
  164.         throw new ArgumentException("regionId.IsValid == false");
  165.  
  166.       if(regionId.ObjectClass.Name != "AcDbRegion")
  167.         throw new ArgumentException("regionId.ObjectClass.Name != AcDbRegion");
  168.  
  169.       if(pcsFileName == null)
  170.         throw new ArgumentNullException("pcsFileName");
  171.       if(pcsFileName.Trim() == String.Empty)
  172.         throw new ArgumentException("pcsFileName.Trim() == String.Empty");
  173.  
  174.       if(mediaName == null)
  175.         throw new ArgumentNullException("mediaName");
  176.       if(mediaName.Trim() == String.Empty)
  177.         throw new ArgumentException("mediaName.Trim() == String.Empty");
  178.  
  179.       if(outputFileName == null)
  180.         throw new ArgumentNullException("outputFileName");
  181.       if(outputFileName.Trim() == String.Empty)
  182.         throw new ArgumentException("outputFileName.Trim() == String.Empty");
  183.  
  184.       Db.Database previewDb = Hs.WorkingDatabase;
  185.       Db.Database db = null;
  186.       Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
  187.       if(doc == null || doc.IsDisposed)
  188.         return;
  189.  
  190.       Ed.Editor ed = doc.Editor;
  191.       try {
  192.         if(regionId.Database != null && !regionId.Database.IsDisposed) {
  193.           Hs.WorkingDatabase = regionId.Database;
  194.           db = regionId.Database;
  195.         }
  196.         else {
  197.           db = doc.Database;
  198.         }
  199.  
  200.         using(doc.LockDocument()) {
  201.           using(Db.Transaction tr = db.TransactionManager.StartTransaction()) {
  202.             Db.Region region = tr.GetObject(regionId,
  203.             Db.OpenMode.ForRead) as Db.Region;
  204.  
  205.             Db.Extents3d extends = region.GeometricExtents;
  206.             Db.ObjectId modelId = Us.GetBlockModelSpaceId(db);
  207.             Db.BlockTableRecord model = tr.GetObject(modelId,
  208.             Db.OpenMode.ForRead) as Db.BlockTableRecord;
  209.  
  210.             Db.Layout layout = tr.GetObject(model.LayoutId,
  211.             Db.OpenMode.ForRead) as Db.Layout;
  212.  
  213.             using(Pt.PlotInfo pi = new Pt.PlotInfo()) {
  214.               pi.Layout = model.LayoutId;
  215.  
  216.               using(Db.PlotSettings ps = new Db.PlotSettings(layout.ModelType)
  217.                 ) {
  218.  
  219.                 ps.CopyFrom(layout);
  220.  
  221.                 Db.PlotSettingsValidator psv = Db.PlotSettingsValidator
  222.                   .Current;
  223.  
  224.                 Gm.Point2d bottomLeft = Gm.Point2d.Origin;
  225.                 Gm.Point2d topRight = Gm.Point2d.Origin;
  226.  
  227.                 region.GetVisualBoundary(0.1, ref bottomLeft,
  228.                   ref topRight);
  229.  
  230.                 Gm.Point3d bottomLeft_3d = new Gm.Point3d(bottomLeft.X,
  231.                   bottomLeft.Y, 0);
  232.                 Gm.Point3d topRight_3d = new Gm.Point3d(topRight.X, topRight.Y,
  233.                   0);
  234.  
  235.                 Db.ResultBuffer rbFrom = new Db.ResultBuffer(new Db.TypedValue(
  236.                   5003, 0));
  237.                 Db.ResultBuffer rbTo = new Db.ResultBuffer(new Db.TypedValue(
  238.                   5003, 2));
  239.  
  240.                 double[] firres = new double[] { 0, 0, 0 };
  241.                 double[] secres = new double[] { 0, 0, 0 };
  242.  
  243.                 acedTrans(bottomLeft_3d.ToArray(), rbFrom.UnmanagedObject,
  244.                   rbTo.UnmanagedObject, 0, firres);
  245.                 acedTrans(topRight_3d.ToArray(), rbFrom.UnmanagedObject,
  246.                   rbTo.UnmanagedObject, 0, secres);
  247.  
  248.                 Db.Extents2d extents = new Db.Extents2d(
  249.                     firres[0],
  250.                     firres[1],
  251.                     secres[0],
  252.                     secres[1]
  253.                   );
  254.  
  255.                 psv.SetZoomToPaperOnUpdate(ps, true);
  256.  
  257.                 psv.SetPlotWindowArea(ps, extents);
  258.                 psv.SetPlotType(ps, Db.PlotType.Window);
  259.                 psv.SetUseStandardScale(ps, true);
  260.                 psv.SetStdScaleType(ps, Db.StdScaleType.ScaleToFit);
  261.                 psv.SetPlotCentered(ps, true);
  262.                 psv.SetPlotRotation(ps, Db.PlotRotation.Degrees000);
  263.  
  264.                 // We'll use the standard DWF PC3, as
  265.                 // for today we're just plotting to file
  266.                 psv.SetPlotConfigurationName(ps, pcsFileName, mediaName);
  267.  
  268.                 // We need to link the PlotInfo to the
  269.                 // PlotSettings and then validate it
  270.                 pi.OverrideSettings = ps;
  271.                 Pt.PlotInfoValidator piv = new Pt.PlotInfoValidator();
  272.                 piv.MediaMatchingPolicy = Pt.MatchingPolicy.MatchEnabled;
  273.                 piv.Validate(pi);
  274.  
  275.                 // A PlotEngine does the actual plotting
  276.                 // (can also create one for Preview)
  277.                 if(Pt.PlotFactory.ProcessPlotState == Pt.ProcessPlotState
  278.                   .NotPlotting) {
  279.                   using(Pt.PlotEngine pe = Pt.PlotFactory.CreatePublishEngine()
  280.                     ) {
  281.                     // Create a Progress Dialog to provide info
  282.                     // and allow thej user to cancel
  283.  
  284.                     using(Pt.PlotProgressDialog ppd =
  285.                       new Pt.PlotProgressDialog(false, 1, true)) {
  286.                       ppd.set_PlotMsgString(
  287.                       Pt.PlotMessageIndex.DialogTitle, "Custom Plot Progress");
  288.  
  289.                       ppd.set_PlotMsgString(
  290.                         Pt.PlotMessageIndex.CancelJobButtonMessage,
  291.                         "Cancel Job");
  292.  
  293.                       ppd.set_PlotMsgString(
  294.                       Pt.PlotMessageIndex.CancelSheetButtonMessage,
  295.                       "Cancel Sheet");
  296.  
  297.                       ppd.set_PlotMsgString(
  298.                       Pt.PlotMessageIndex.SheetSetProgressCaption,
  299.                       "Sheet Set Progress");
  300.  
  301.                       ppd.set_PlotMsgString(
  302.                         Pt.PlotMessageIndex.SheetProgressCaption,
  303.                        "Sheet Progress");
  304.  
  305.                       ppd.LowerPlotProgressRange = 0;
  306.                       ppd.UpperPlotProgressRange = 100;
  307.                       ppd.PlotProgressPos = 0;
  308.  
  309.                       // Let's start the plot, at last
  310.                       ppd.OnBeginPlot();
  311.                       ppd.IsVisible = true;
  312.                       pe.BeginPlot(ppd, null);
  313.  
  314.                       // We'll be plotting a single document
  315.                       pe.BeginDocument(pi, doc.Name, null, 1, true,
  316.                         // Let's plot to file
  317.                        outputFileName);
  318.                       // Which contains a single sheet
  319.                       ppd.OnBeginSheet();
  320.                       ppd.LowerSheetProgressRange = 0;
  321.                       ppd.UpperSheetProgressRange = 100;
  322.                       ppd.SheetProgressPos = 0;
  323.                       Pt.PlotPageInfo ppi = new Pt.PlotPageInfo();
  324.                       pe.BeginPage(ppi, pi, true, null);
  325.                       pe.BeginGenerateGraphics(null);
  326.                       pe.EndGenerateGraphics(null);
  327.  
  328.                       // Finish the sheet
  329.                       pe.EndPage(null);
  330.                       ppd.SheetProgressPos = 100;
  331.                       ppd.OnEndSheet();
  332.  
  333.                       // Finish the document
  334.                       pe.EndDocument(null);
  335.  
  336.                       // And finish the plot
  337.                       ppd.PlotProgressPos = 100;
  338.                       ppd.OnEndPlot();
  339.                       pe.EndPlot(null);
  340.                     }
  341.                   }
  342.                 }
  343.                 else {
  344.                   ed.WriteMessage("\nAnother plot is in progress.");
  345.                 }
  346.               }
  347.             }
  348.             tr.Commit();
  349.           }
  350.         }
  351.       }
  352.       finally {
  353.         Hs.WorkingDatabase = previewDb;
  354.       }
  355.     }
  356.   }
  357. }
  358.  
« Последнее редактирование: 12-06-2014, 08:34:05 от Андрей Бушман »

Оффлайн Александр Ривилис

  • Administrator
  • *****
  • Сообщений: 13829
  • Карма: 1784
  • Рыцарь ObjectARX
  • Skype: rivilis
Re: Нюансы использования acedTrans
« Ответ #1 : 12-06-2014, 00:31:11 »
Обратил внимание на неточность, связанную с копипастом кода Киана. Вспоминаем, что в его коде координаты "окна" указываются на экране, т.е. в ПСК (UCS). У тебя же все координаты в МСК (WCS). Отсюда следует необходимость заменить:
Код - C# [Выбрать]
  1. Db.ResultBuffer rbFrom = new Db.ResultBuffer(new Db.TypedValue(5003, 1));
на
Код - C# [Выбрать]
  1. Db.ResultBuffer rbFrom = new Db.ResultBuffer(new Db.TypedValue(5003, 0));
В противном случае ты будешь печатать не ту область.
Не забывайте про правильное Форматирование кода на форуме
Создание и добавление Autodesk Screencast видео в сообщение на форуме
Если Вы задали вопрос и на форуме появился правильный ответ, то не забудьте про кнопку Решение

Оффлайн Андрей БушманАвтор темы

  • ADN Club
  • *****
  • Сообщений: 2000
  • Карма: 163
  • Пишу программки...
    • Блог
  • Skype: Compositum78
Re: Нюансы использования acedTrans
« Ответ #2 : 12-06-2014, 08:27:41 »
Спасибо, подправлю. Поскольку перед началом работы система координат устанавливается в мировую (программно), то в виду этого я получал корректную публикацию (совпадение).