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
);
[CommandMethod("winplot")]
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[0],
firres[1],
secres[0],
secres[1]
);
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."
);
}
}
}
}
}

Subscribe via RSS
Hi Kean.
You can use Point3d directly in P/Invoke where the parameter is an ads_point (note the use of the 'out' param modifier for output params):
Posted by: Tony Tanzillo | October 13, 2007 at 01:30 PM
Thanks, Tony.
In this case it doesn't really improve the flow of the code, as we need to create an Extents2d object from the results. But it's certainly a good tip for cases where Point3ds are to be used afterwards.
Regards,
Kean
Posted by: Kean | October 13, 2007 at 02:04 PM
Hello Kean,
I am trying to print Autocad file using .NET windows application. I am not able to find Autodesk in my using function. Can you guide me how to do this?
It will be better if I could get code to accomplish this. I have autocad 2007 installed in my system.
Thanks and Warm Regards,
Sudarshan
Posted by: sudarshan | October 19, 2007 at 12:35 PM
Hi Sudarshan,
You will need to set a project reference to acmgd.dll and acdbmgd.dll (in the AutoCAD install folder).
Check out this introductory post, which talks about using the ObjectARX Wizard to set your project up.
Regards,
Kean
Posted by: Kean | October 22, 2007 at 11:50 AM
Hi Kean,
Thank you for the reply. I am able to set project references. How do I print the Autocad drawing from .NET? I was not able to find the solutions on internet.
Is there any function in Autocad that can take path of drawing and print it to printer?
Regards,
Sudarshan
Posted by: sudarshan | October 23, 2007 at 10:07 AM
Hi Sudarshan,
Not a single function - there's a complete Plotting API that does this. Take a look at the posts under "Plotting".
Regards,
Kean
Posted by: Kean | October 23, 2007 at 10:14 AM
Hi Kean,
Can you send me code from which I can achieve plotting of drawing from .NET?
I had a look at the plotting, but was not able to understand since input is taken from Autocad.
I am in really need of this.
Regards,
Sudarshan
Posted by: sudarshan | October 23, 2007 at 11:01 AM
Sudarshan - I don't understand what it is you want that's different from what's posted. All those posts plot drawings in different ways (whether single or multi-sheet, or with/without preview).
If you're trying to do this without AutoCAD running (which you did not state in your previous comments) then it won't work, I'm afraid.
Regards,
Kean
Posted by: Kean | October 23, 2007 at 11:05 AM
Hi Kean,
Can you send the project file to my email id? I will try to trace the application from beginning. Also I am not able to incorporate your code into my application.
regards,
Sudarshan
Posted by: sudarshan | October 23, 2007 at 01:01 PM
Hi Sudarshan,
I'm sorry - if I start providing this kind of custom support, it'll never end. I help when there are specific issues with my posts, but otherwise it's just not feasible.
Please post to the .NET discussion group or request help from my team via the Autodesk Developer Network (if you're a member).
Also, the AutoCAD Developer Center has a lot of helpful "getting started" information, including some Labs for AutoCAD .NET.
Regards,
Kean
Posted by: Kean | October 23, 2007 at 01:20 PM
Kean,
When I include your code into my application it says " Application' is an ambiguous reference". Can you guide me how to solve this error?
Regards,
Sudarshan
Posted by: sudarshan | October 24, 2007 at 08:08 AM
Sudarshan,
It's probably because you're including System.Windows.Forms:
using System.Windows.Forms;
Both this and Autodesk.AutoCAD.ApplicationServices include an Application type. So you need to disambiguate the use of Application by prefixing the use of Application with the relevant namespace (for instance).
Regards,
Kean
Posted by: Kean | October 24, 2007 at 08:20 AM
How do I solver this error?
An unhandled exception of type 'System.IO.FileNotFoundException' occurred in WindowsApplication6.exe
Additional information: File or assembly name acdbmgd, or one of its dependencies, was not found.
Regards,
Sudarshan
Posted by: sudarshan | October 24, 2007 at 08:27 AM
Sudarshan - please post your introductory support-related question to the ADN team or the .NET discussion group.
Regards,
Kean
Posted by: Kean | October 24, 2007 at 08:31 AM
I shall do that Kean.
Is there any way to Converting autocad drawing into PDF format?
Regards,
Sudarshan
Posted by: sudarshan | October 24, 2007 at 08:34 AM
You will need to plot. You can use the standard "DWG to PDF.pc3" device or a 3rd party printer driver.
Kean
Posted by: Kean | October 24, 2007 at 09:24 AM
What has to be included to get AutoDesk.AutoCAD.Interop.Application?
Sudarshan
Posted by: sudarshan | October 24, 2007 at 09:39 AM
Kean,
Can you tell me which part of code has to be used just to plot(Without selecting the points)? I need to plot the drawing file.
Sudarshan
Posted by: sudarshan | October 24, 2007 at 10:23 AM
Good stuff Kean,
You've been kicked (a good thing) - Trackback from CadKicks.com
http://www.cadkicks.com/adkautocad/Plotting_a_window_from_AutoCAD_using_NET
Posted by: CadKicks.com | November 10, 2007 at 02:40 PM
Can anybody explain howthe code works
Posted by: Sony | November 14, 2007 at 05:02 AM
Sony -
I'd suggest downloading the ObjectARX SDK (http://www.autodesk.com/objectarx) and looking at the documentation... it is mainly covering ObjectARX, but the .NET layer is very "thin", so the descriptions should be adequate for both environments (although not ideal).
Kean
Posted by: Kean | November 14, 2007 at 09:56 AM
Thanks Kean,
Actually i wanted to ask can i get sample code for custom plotting of autocad layout drawings from .net using vb.net.My application will be having a interface where it will show the plotter set,and also scale options and user can select any layout which displayed in the listbox provided.
basically a plotter manager .net application which will take layout drawings and send it for plotting according to the settings made by the user.
And i also wanted a sample code as how to convert Autocad file to PDF Format without opening autocad
Posted by: Sony | November 15, 2007 at 05:48 AM
i want to load a dll automatically when autocad 2008 opens instead of using netload.can any one help?
Posted by: Sony | November 15, 2007 at 05:59 AM
how to avoid proxy information dialog box from appearing while openeing a autocad civil 3d 2008 drawing in autocad 2008.
Proxy information:Drawing contains objectARX entities.
Posted by: Sony | November 15, 2007 at 06:05 AM
Sony,
Please post your questions to the AutoCAD .NET Discussion Group - this is not the right forum.
BTW - check out this post for the automatic loading question.
Regards,
Kean
Posted by: Kean | November 15, 2007 at 08:26 AM