using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using cad = Autodesk.AutoCAD.ApplicationServices.Application;
using Ap = Autodesk.AutoCAD.ApplicationServices;
using Db = Autodesk.AutoCAD.DatabaseServices;
using Ed = Autodesk.AutoCAD.EditorInput;
using Rt = Autodesk.AutoCAD.Runtime;
using Gm = Autodesk.AutoCAD.Geometry;
using Wn = Autodesk.AutoCAD.Windows;
using Hs = Autodesk.AutoCAD.DatabaseServices.HostApplicationServices;
using Us = Autodesk.AutoCAD.DatabaseServices.SymbolUtilityServices;
using Br = Autodesk.AutoCAD.BoundaryRepresentation;
using Pt = Autodesk.AutoCAD.PlottingServices;
// для возможности использования методов расширений
using Autodesk.AutoCAD.ApplicationServices;
using Bushman.CAD.Extensions;
[assembly: Rt.CommandClass(typeof(Bushman.CAD.Commands.PlotProblem))]
namespace Bushman.CAD.Commands {
public sealed class PlotProblem {
#if AUTOCAD_NEWER_THAN_2012
const String acedTransOwner = "accore.dll";
#else
const String acedTransOwner = "acad.exe";
#endif
#if AUTOCAD_NEWER_THAN_2014
const String acedTrans_x86_Prefix = "_";
#else
const String acedTrans_x86_Prefix = "";
#endif
const String acedTransName = "acedTrans";
[DllImport(acedTransOwner, CallingConvention = CallingConvention.Cdecl,
EntryPoint = acedTrans_x86_Prefix + acedTransName)]
static extern Int32 acedTrans_x86(Double[] point, IntPtr fromRb,
IntPtr toRb, Int32 disp, Double[] result);
[DllImport(acedTransOwner, CallingConvention = CallingConvention.Cdecl,
EntryPoint = acedTransName)]
static extern Int32 acedTrans_x64(Double[] point, IntPtr fromRb,
IntPtr toRb, Int32 disp, Double[] result);
internal static Int32 acedTrans(Double[] point, IntPtr fromRb, IntPtr toRb,
Int32 disp, Double[] result) {
if(IntPtr.Size == 4)
return acedTrans_x86(point, fromRb, toRb, disp, result);
else
return acedTrans_x64(point, fromRb, toRb, disp, result);
}
/// <summary>
/// Печать объектов базы данных согласно указанным границам печати
/// (Window).
/// </summary>
/// <param name="db">База данных, объекты которой подлежат публикации.
/// </param>
/// <param name="bottomLeft">Левый нижний угол границы печати.
/// </param>
/// <param name="topRight">Правый верхний угол границы печати.
/// </param>
/// <param name="pcsFileName">Наименование PC3 файла</param>
/// <param name="mediaName">Наименование выбранного формата листа</param>
/// <param name="outputFileName">Имя файла, в котором сохраняется результат
/// печати.</param>
public static void PlotRegion(Db.Database db, Gm.Point2d bottomLeft,
Gm.Point2d topRight, String pcsFileName, String mediaName,
String outputFileName, String dwgFileName) {
Ed.Editor ed = cad.DocumentManager.MdiActiveDocument.Editor;
try {
if(db == null)
throw new ArgumentNullException("db");
if(db.IsDisposed)
throw new ArgumentException("db.IsDisposed == true");
if(pcsFileName == null)
throw new ArgumentNullException("pcsFileName");
if(pcsFileName.Trim() == String.Empty)
throw new ArgumentException("pcsFileName.Trim() == String.Empty");
if(mediaName == null)
throw new ArgumentNullException("mediaName");
if(mediaName.Trim() == String.Empty)
throw new ArgumentException("mediaName.Trim() == String.Empty");
if(outputFileName == null)
throw new ArgumentNullException("outputFileName");
if(outputFileName.Trim() == String.Empty)
throw new ArgumentException("outputFileName.Trim() == String.Empty");
using(Db.Transaction tr = db.TransactionManager.StartTransaction()) {
Db.ObjectId modelId = Us.GetBlockModelSpaceId(db);
Db.BlockTableRecord model = tr.GetObject(modelId,
Db.OpenMode.ForRead) as Db.BlockTableRecord;
Db.Layout layout = tr.GetObject(model.LayoutId,
Db.OpenMode.ForRead) as Db.Layout;
using(Pt.PlotInfo pi = new Pt.PlotInfo()) {
pi.Layout = model.LayoutId;
using(Db.PlotSettings ps = new Db.PlotSettings(layout.ModelType)
) {
ps.CopyFrom(layout);
Db.PlotSettingsValidator psv = Db.PlotSettingsValidator
.Current;
Gm.Point3d bottomLeft_3d = new Gm.Point3d(bottomLeft.X,
bottomLeft.Y, 0);
Gm.Point3d topRight_3d = new Gm.Point3d(topRight.X, topRight.Y,
0);
Db.ResultBuffer rbFrom = new Db.ResultBuffer(new Db.TypedValue(
5003, 1));
Db.ResultBuffer rbTo = new Db.ResultBuffer(new Db.TypedValue(
5003, 2));
double[] firres = new double[] { 0, 0, 0 };
double[] secres = new double[] { 0, 0, 0 };
acedTrans(bottomLeft_3d.ToArray(), rbFrom.UnmanagedObject,
rbTo.UnmanagedObject, 0, firres);
acedTrans(topRight_3d.ToArray(), rbFrom.UnmanagedObject,
rbTo.UnmanagedObject, 0, secres);
Db.Extents2d extents = new Db.Extents2d(
firres[0],
firres[1],
secres[0],
secres[1]
);
psv.SetZoomToPaperOnUpdate(ps, true);
// Прежде чем методу SetPlotType присвоить в качестве второго
// параметра значение PlotType.Window, необходимо вызвать метод
// SetPlotWindowArea, указав через него границы Window.
// В противном случае возникнет runtime error.
psv.SetPlotWindowArea(ps, extents);
psv.SetPlotType(ps, Db.PlotType.Window);
psv.SetUseStandardScale(ps, true);
psv.SetStdScaleType(ps, Db.StdScaleType.ScaleToFit);
psv.SetPlotCentered(ps, true);
psv.SetPlotRotation(ps, Db.PlotRotation.Degrees000);
// We'll use the standard DWF PC3, as
// for today we're just plotting to file
psv.SetPlotConfigurationName(ps, pcsFileName, mediaName);
// We need to link the PlotInfo to the
// PlotSettings and then validate it
pi.OverrideSettings = ps;
Pt.PlotInfoValidator piv = new Pt.PlotInfoValidator();
piv.MediaMatchingPolicy = Pt.MatchingPolicy.MatchEnabled;
piv.Validate(pi);
// A PlotEngine does the actual plotting
// (can also create one for Preview)
if(Pt.PlotFactory.ProcessPlotState == Pt.ProcessPlotState
.NotPlotting) {
using(Pt.PlotEngine pe = Pt.PlotFactory.CreatePublishEngine()
) {
// Create a Progress Dialog to provide info
// and allow thej user to cancel
using(Pt.PlotProgressDialog ppd =
new Pt.PlotProgressDialog(false, 1, true)) {
ppd.set_PlotMsgString(
Pt.PlotMessageIndex.DialogTitle, "Custom Plot Progress");
ppd.set_PlotMsgString(
Pt.PlotMessageIndex.CancelJobButtonMessage,
"Cancel Job");
ppd.set_PlotMsgString(
Pt.PlotMessageIndex.CancelSheetButtonMessage,
"Cancel Sheet");
ppd.set_PlotMsgString(
Pt.PlotMessageIndex.SheetSetProgressCaption,
"Sheet Set Progress");
ppd.set_PlotMsgString(
Pt.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, dwgFileName, null, 1, true,
// Let's plot to file
outputFileName);
// Which contains a single sheet
ppd.OnBeginSheet();
ppd.LowerSheetProgressRange = 0;
ppd.UpperSheetProgressRange = 100;
ppd.SheetProgressPos = 0;
Pt.PlotPageInfo ppi = new Pt.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);
}
}
}
}
}
tr.Commit();
}
}
catch(Exception ex) {
ed.WriteMessage("\n{0}\n", ex.Message);
}
}
/// <summary>
/// Опубликовать в PDF файл все регионы, находящиеся в пространстве модели
/// указанного пользователем DWG файла.
/// </summary>
[Rt.CommandMethod("PlotToPdf", Rt.CommandFlags.Session)]
public void PlotToPdfCommand() {
Ap.Document doc = cad.DocumentManager.MdiActiveDocument;
if(doc == null || doc.IsDisposed)
return;
Ed.Editor ed = doc.Editor;
Db.Database db = doc.Database;
using(doc.LockDocument()) {
Microsoft.Win32.OpenFileDialog openFileDialog = new Microsoft.Win32
.OpenFileDialog();
openFileDialog.Title =
"Выберите DWG файл, подлежащий публикации в PDF";
openFileDialog.Filter = "DWG-файлы|*.dwg";
bool? result = openFileDialog.ShowDialog();
if(!result.HasValue || !result.Value) {
ed.WriteMessage("\nВыполнение команды прервано, т.к. не был указан "
+ "DWG-файл.");
return;
}
String dwgFileName = openFileDialog.FileName;
String pdfFileName = System.IO.Path.GetFileNameWithoutExtension(
dwgFileName) + ".pdf";
String pdfFileFullName = System.IO.Path.Combine(System.IO.Path
.GetDirectoryName(dwgFileName), pdfFileName);
MessageBoxResult mbResult = MessageBox.Show(
"Печатать не создавая Document?", "Вопрос", MessageBoxButton.YesNo,
MessageBoxImage.Question);
if(mbResult == MessageBoxResult.Yes) {
Gm.Point2d bottomLeft = Gm.Point2d.Origin;
Gm.Point2d topRight = Gm.Point2d.Origin;
Db.Database old = Hs.WorkingDatabase;
try {
using(Db.Database outputDb = new Db.Database(true, true)) {
outputDb.ReadDwgFile(dwgFileName,
Db.FileOpenMode.OpenForReadAndReadShare, true, String.Empty);
Hs.WorkingDatabase = outputDb;
using(Db.Transaction tr = outputDb.TransactionManager
.StartTransaction()) {
Db.BlockTableRecord model = tr.GetObject(
Us.GetBlockModelSpaceId(outputDb), Db.OpenMode.ForRead)
as Db.BlockTableRecord;
List<Db.Region> regions = new List<Db.Region>();
foreach(Db.ObjectId id in model) {
if(id.ObjectClass.Name == "AcDbRegion") {
Db.Region region = tr.GetObject(id, Db.OpenMode.ForRead)
as Db.Region;
regions.Add(region);
}
}
GetCommonVisualBoundary(regions, 0.1, ref bottomLeft,
ref topRight);
String formatName = "ISO_A4_(210.00_x_297.00_MM)";
if((topRight.X - bottomLeft.X) > (topRight.Y - bottomLeft.Y))
formatName = "ISO_A4_(297.00_x_210.00_MM)";
PlotRegion(outputDb, bottomLeft, topRight,
"DWG To PDF.pc3", formatName, pdfFileFullName, dwgFileName);
tr.Commit();
}
}
}
finally {
Hs.WorkingDatabase = old;
}
ed.WriteMessage("\nПубликация выполнена в файл \"{0}\"\n",
pdfFileFullName);
}
else {
Ap.Document doc2 = cad.DocumentManager.Open(dwgFileName, false);
Db.Database db2 = doc2.Database;
Ed.Editor ed2 = doc2.Editor;
using(Db.Transaction tr = db2.TransactionManager.StartTransaction()
) {
List<Db.Region> regions = new List<Db.Region>();
Db.BlockTableRecord model = tr.GetObject(Us.GetBlockModelSpaceId(
db2), Db.OpenMode.ForRead) as Db.BlockTableRecord;
foreach(Db.ObjectId id in model) {
if(id.ObjectClass.Name == "AcDbRegion") {
Db.Region region = tr.GetObject(id, Db.OpenMode.ForRead)
as Db.Region;
regions.Add(region);
}
}
String formatName = "ISO_A4_(210.00_x_297.00_MM)";
Gm.Point2d bottomLeft = Gm.Point2d.Origin;
Gm.Point2d topRight = Gm.Point2d.Origin;
GetCommonVisualBoundary(regions, 0.1, ref bottomLeft,
ref topRight);
if((topRight.X - bottomLeft.X) > (topRight.Y - bottomLeft.Y))
formatName = "ISO_A4_(297.00_x_210.00_MM)";
PlotRegion(db2, bottomLeft, topRight, "DWG To PDF.pc3",
formatName, pdfFileFullName, dwgFileName);
tr.Commit();
ed2.WriteMessage("\nПубликация выполнена в файл \"{0}\"\n",
pdfFileFullName);
}
}
}
}
/// <summary>
/// Получить координаты границ левого нижнего и правого верхнего углов для
/// общего визуального "GeometricExtents" указанных регионов.
/// </summary>
/// <param name="regions">Регионы, для которых следует получить общие
/// координаты границ визуального "GeometricExtents".</param>
/// <param name="delta">Предельная арифметическая погрешность вычислений.
/// </param>
/// <param name="minPoint">Ссылка на переменную Point2d, в которой следует
/// сохранить координаты левого нижнего угла визуального
/// "GeometricExtents".</param>
/// <param name="maxPoint">Ссылка на переменную Point2d, в которой следует
/// сохранить координаты правого верхнего угла визуального
/// "GeometricExtents".</param>
public static void GetCommonVisualBoundary(IEnumerable<Db.Region>
regions, Double delta, ref Gm.Point2d minPoint, ref Gm.Point2d maxPoint
) {
Double minX = Double.MaxValue;
Double minY = Double.MaxValue;
Double maxX = Double.MinValue;
Double maxY = Double.MinValue;
Gm.Point2d tmpMin = Gm.Point2d.Origin;
Gm.Point2d tmpMax = Gm.Point2d.Origin;
foreach(Db.Region region in regions) {
GetVisualBoundary(region, delta, ref tmpMin, ref tmpMax);
minX = Math.Min(minX, tmpMin.X);
minY = Math.Min(minY, tmpMin.Y);
maxX = Math.Max(maxX, tmpMax.X);
maxY = Math.Max(maxY, tmpMax.Y);
}
minPoint = new Gm.Point2d(minX, minY);
maxPoint = new Gm.Point2d(maxX, maxY);
}
/// <summary>
/// Получить координаты границ левого нижнего и правого верхнего углов для
/// визуального "GeometricExtents" региона.
/// </summary>
/// <param name="region">Регион, для которого следует получить координаты
/// границ визуального "GeometricExtents".</param>
/// <param name="delta">Предельная арифметическая погрешность вычислений.
/// </param>
/// <param name="minPoint">Ссылка на переменную Point2d, в которой следует
/// сохранить координаты левого нижнего угла визуального
/// "GeometricExtents".</param>
/// <param name="maxPoint">Ссылка на переменную Point2d, в которой следует
/// сохранить координаты правого верхнего угла визуального
/// "GeometricExtents".</param>
public static void GetVisualBoundary(Db.Region region, Double delta,
ref Gm.Point2d minPoint, ref Gm.Point2d maxPoint) {
using(Gm.BoundBlock3d boundBlk = new Gm.BoundBlock3d()) {
using(Br.Brep brep = new Br.Brep(region)) {
foreach(Br.Edge edge in brep.Edges) {
using(Gm.Curve3d curve = edge.Curve) {
Gm.ExternalCurve3d curve3d = curve as Gm.ExternalCurve3d;
// Делать точный расчет нужно только если образующая - сплайн
// в противном случае достаточно получить BoundBlock
if(curve3d != null && curve3d.IsNurbCurve) {
using(Gm.NurbCurve3d nurbCurve = curve3d.NativeCurve
as Gm.NurbCurve3d) {
Gm.Interval interval = nurbCurve.GetInterval();
for(double par = interval.LowerBound; par <=
interval.UpperBound; par += (delta * 2.0)) {
Gm.Point3d p = nurbCurve.EvaluatePoint(par);
if(!boundBlk.IsBox)
boundBlk.Set(p, p);
else
boundBlk.Extend(p);
}
}
}
else {
if(!boundBlk.IsBox) {
boundBlk.Set(edge.BoundBlock.GetMinimumPoint(),
edge.BoundBlock.GetMaximumPoint());
}
else {
boundBlk.Extend(edge.BoundBlock.GetMinimumPoint());
boundBlk.Extend(edge.BoundBlock.GetMaximumPoint());
}
}
}
}
}
boundBlk.Swell(delta);
// Возвращаем вычисленный результат
minPoint = new Gm.Point2d(boundBlk.GetMinimumPoint().X,
boundBlk.GetMinimumPoint().Y);
maxPoint = new Gm.Point2d(boundBlk.GetMaximumPoint().X,
boundBlk.GetMaximumPoint().Y);
}
}
}
}