AutoCAD按坐标打印图纸
前几天,我所在公司面临了一项需求:根据坐标在特定DWG文件中按指定位置打印Block引用的图像。完成这一任务涉及多个步骤和一些解难环节,我在此真诚地分享解决方案,一起解决问题,节省后来者的时间和精力。
设计需求与挑战:我们公司的设计图纸以Autodesk的AutoCAD 2010版本创建,一般来说,一个项目的所有图纸存储在一个单一的DWG文件中。这些图纸按照不同目的嵌入在不同Block引用(块)中。我的任务是定位并打印这些Block引用的精确位置,具体即通过AutoCAD .NET API,获取Block引用轮廓内的左下角和右上角点的坐标。如果精确动作切错了路径,那么将会一眼望见空白的打印输出,而非预期标准的图纸集锦。
实现策略与关键代码:
1. 使用AutoCAD .NET API:我们决定采用AutoCAD的.NET API,找到并筛选目标坐标。API以原点作为起点追踪,特殊之处在于它的坐标系并不总与打印设备的坐标系保持一致。因此,我们采用两种坐标系表述块引用的边界,确保两者相匹配以便打印。
2. 解决坐标体系的不兼容问题:发现常见的问题是某些图纸在打印时仅输出空白图像,这显然与坐标系统存在关联。在AutoCAD中,存在几种不同类型的坐标系统:UCS(用户坐标系统)、DCS(显示设备坐标系统)及UCS坐标。UCS是基础坐标系统,其他如DCS都是基于UCS推衍而来。在我们的打印操作中,API输出的块引用坐标是原点(UCS)坐标系,打印指令则需要DCS坐标系。因此,不进行UCS到DCS的转换会导致打印空白图。
3. 通过ObjectARX引入acedTrans()函数:遗憾的是,进行坐标系转换的复杂操作,直接使用API并不提供这一功能。幸运的是,结合了ObjectARX提供的acedTrans()函数,我们致力于整合这一功能,确保坐标转换得以实现。这一函数允许我们:根据给定的坐标点,将其从一个坐标系转换为其他坐标系。我们不仅引入了这一功能并整合到了我们的自定义操作中,还优化了特定的函数:
```csharp
public partial class BlockSelectForm : Form
{
[DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acedTrans")]
static extern int acedTrans(
double[] point,
IntPtr fromRb,
IntPtr toRb,
int disp,
double[] result);
private Extents2d Ucs2Dcs(Point3d objStart, Point3d objEnd)
{
ResultBuffer rbFrom = new ResultBuffer(new TypedValue(5003, 1));
ResultBuffer rbTo = new ResultBuffer(new TypedValue(5003, 2));
double[] firres = new double[] { 0, 0, 0 };
double[] secres = new double[] { 0, 0, 0 };
acedTrans(
objStart.ToArray(),
rbFrom.UnmanagedObject,
rbTo.UnmanagedObject,
0,
firres);
acedTrans(
objEnd.ToArray(),
rbFrom.UnmanagedObject,
rbTo.UnmanagedObject,
0,
secres);
Extents2d window = new Extents2d(
firres[0],
firres[1],
secres[0],
secres[1]);
return window;
}
}
```
接下来,使用上述坐标转换方法,我们制定了一个有效的打印界面,事半功倍:
```csharp
private string PrintBMP(Point3d objStart, Point3d objEnd, string strPrintName, string strPaperName, string strStyleName, string strRotation)
{
Document acDoc = Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument;
Database acCurDb = acDoc.Database;
Extents2d objPoint = Ucs2Dcs(objStart, objEnd);
string strFileName = string.Empty;
// 开始事务
using (Transaction acTrans = acCurDb.TransactionManager.StartTransaction())
{
// 加载布局块表记录
BlockTableRecord btr = (BlockTableRecord)acTrans.GetObject(acCurDb.CurrentSpaceId, OpenMode.ForRead);
Layout acLayout = (Layout)acTrans.GetObject(btr.LayoutId, OpenMode.ForRead);
// 加载布局的打印信息
PlotInfo acPlInfo = new PlotInfo();
acPlInfo.Layout = btr.LayoutId;
// 复制布局的打印设置
PlotSettings acPlSet = new PlotSettings(acLayout.ModelType);
acPlSet.CopyFrom(acLayout);
// 使用布局验证器进行参数化设置
PlotSettingsValidator acPlSetVdr = PlotSettingsValidator.Current;
acPlSetVdr.SetPlotWindowArea(acPlSet, objPoint);
acPlSetVdr.SetPlotType(acPlSet, ((Autodesk.AutoCAD.DatabaseServices.PlotType.Window)));
acPlSetVdr.SetUseStandardScale(acPlSet, true);
acPlSetVdr.SetStdScaleType(acPlSet, StdScaleType.ScaleToFit);
acPlSetVdr.SetPlotCentered(acPlSet, true);
// 设置打印机名称、纸张大小等
acPlSetVdr.SetPlotConfigurationName(
acPlSet,
strPrintName,
strPaperName);
acPlSetVdr.RefreshLists(acPlSet);
acPlSetVdr.SetCurrentStyleSheet(acPlSet, strStyleName);
// 设置旋转角度
switch (strRotation)
{
case "0":
acPlSetVdr.SetPlotRotation(acPlSet, PlotRotation.Degrees000);
break;
case "90":
acPlSetVdr.SetPlotRotation(acPlSet, PlotRotation.Degrees090);
break;
case "180":
acPlSetVdr.SetPlotRotation(acPlSet, PlotRotation.Degrees180);
break;
case "270":
acPlSetVdr.SetPlotRotation(acPlSet, PlotRotation.Degrees270);
break;
}
// 打印输出动作
// (此处省略实际的打印输出代码)
}
return strFileName;
}
```
通过这些代码示例和实施策略的概述分享,不仅解决了在AutoCAD中按坐标打印DWG文件时面临的若干挑战,而且希望这一分享能够为团队节省大量人力与时间,使得后续任务的执行更加顺利,效率也得到显著提升。在此,我想特别感谢业界知名专家Kean的无私指导,让我能够深入理解并通过实践解决了这一复杂问题,助力项目的成功推进。