Is there a way to create a 3D DWF from a drawing using VB.Net? I have a program that processes hundreds of drawings and creates a PDF and DWF of each drawing. I'd like to also create a 3D DWF file, but haven't find anything on it anywhere. I'm not sure if this would be a Save As, Export or something else.
Thanks,
Ken
Solved! Go to Solution.
Solved by _gile. Go to Solution.
Solved by _gile. Go to Solution.
Hi Ken,
If it appropriate and you are happy using the command line then use "3DDWF"
Adam
Adam,
I thought about that, but the SendStringToExecute doesn't run until everything else has finished in vb.net (which doesn't work when batch processing). And since moving to the 2013 API, I've found that emulating the vba "ThisDrawing.SendCommand" is spotty at best. Though, I may have to go this route if there is not a direct way to access it.
Thanks,
Ken
Hi,
You can P/Invoke acedCmd which is synchronous.
Here's another way, in pure .NET. Maybe it isn't the best one but it works fine for me.
It creates a DSD file and publish it.
In this example, all layouts are published to DWF and the Model to 3d DWF
using System.IO; using System.Text; using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoCAD.EditorInput; using Autodesk.AutoCAD.Geometry; using Autodesk.AutoCAD.PlottingServices; using Autodesk.AutoCAD.Publishing; using Autodesk.AutoCAD.Runtime; using AcAp = Autodesk.AutoCAD.ApplicationServices.Application; namespace Publish3dDwf { public class PublishDwf { // Private fields private string dwgFile, dwfFile, dsdFile, tmpFile, title, outputDir; private int numOfSections; private Database db = HostApplicationServices.WorkingDatabase; private Editor ed = AcAp.DocumentManager.MdiActiveDocument.Editor; const string FN_PUBLOG = "publish.log"; // Constructor public PublishDwf() { dwgFile = db.Filename; outputDir = Path.GetDirectoryName(dwgFile); if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir); title = Path.GetFileNameWithoutExtension(dwgFile); dwfFile = Path.ChangeExtension(dwgFile, "dwf"); dsdFile = Path.ChangeExtension(dwgFile, "dsd"); tmpFile = Path.Combine(outputDir, "temp.dsd"); numOfSections = 0; } // Publishes all layouts, displays a progress bar private void Publish() { try { Publisher publisher = AcAp.Publisher; PlotProgressDialog plotDlg = new PlotProgressDialog(false, numOfSections, true); publisher.PublishDsd(dsdFile, plotDlg); plotDlg.Destroy(); } catch (System.Exception ex) { ed.WriteMessage("\nErreur: {0}\n{1}", ex.Message, ex.StackTrace); } } // Creates a DSD file (template) private void CreateDSD() { using (DsdData dsd = new DsdData()) using (DsdEntryCollection dsdEntCol = CreateDsdEntryCollection()) { numOfSections = dsdEntCol.Count; dsd.SetDsdEntryCollection(dsdEntCol); dsd.SetUnrecognizedData("PwdProtectPublishedDWF", "FALSE"); dsd.SetUnrecognizedData("PromptForPwd", "FALSE"); dsd.SheetType = SheetType.MultiDwf; dsd.NoOfCopies = 1; dsd.DestinationName = dwfFile; dsd.IsHomogeneous = false; dsd.LogFilePath = Path.Combine(outputDir, FN_PUBLOG); PostProcessDSD(dsd); } } // Creates an entry collection (one per layout) for the DSD file private DsdEntryCollection CreateDsdEntryCollection() { DsdEntryCollection dsdEntCol = new DsdEntryCollection(); using (Transaction tr = db.TransactionManager.StartTransaction()) { DBDictionary layoutDict = (DBDictionary)tr.GetObject(db.LayoutDictionaryId, OpenMode.ForRead); foreach (DBDictionaryEntry layoutEntry in layoutDict) { Layout layout = (Layout)tr.GetObject(layoutEntry.Value, OpenMode.ForRead); DsdEntry dsdEntry = new DsdEntry(); dsdEntry.DwgName = dwgFile; dsdEntry.Layout = layout.LayoutName.ToString(); dsdEntry.Title = title + "-" + layout.LayoutName; dsdEntry.Nps = layout.TabOrder.ToString(); dsdEntCol.Add(dsdEntry); } } return dsdEntCol; } // Writes the definitive DSD file from the template and additional infos private void PostProcessDSD(DsdData dsd) { string str, newStr; try { dsd.WriteDsd(tmpFile); bool isModel = false; using (StreamReader reader = new StreamReader(tmpFile, Encoding.Default)) using (StreamWriter writer = new StreamWriter(dsdFile, false, Encoding.Default)) { while (!reader.EndOfStream) { str = reader.ReadLine(); if (str == "Layout=Model") { isModel = true; } if (str.Contains("Has3DDWF")) { newStr = isModel ? "Has3DDWF=1" : "Has3DDWF=0"; // <- 3dDwf if Model layout isModel = false; } else if (str.Contains("OriginalSheetPath")) { newStr = "OriginalSheetPath=" + dwgFile; } else if (str.Contains("Type")) { newStr = "Type=0"; // <- 6 for DwgToPdf } else if (str.Contains("OUT")) { newStr = "OUT=" + outputDir; } else if (str.Contains("IncludeLayer")) { newStr = "IncludeLayer=TRUE"; } else if (str.Contains("PromptForDwfName")) { newStr = "PromptForDwfName=FALSE"; } else if (str.Contains("LogFilePath")) { newStr = "LogFilePath=" + Path.Combine(outputDir, FN_PUBLOG); } else { newStr = str; } writer.WriteLine(newStr); } } } catch (System.Exception e) { ed.WriteMessage("\nErreur: {0}\n{1}", e.Message, e.StackTrace); } } // Deletes the DSD files private void Cleanup() { try { if (File.Exists(dsdFile)) { File.Delete(dsdFile); } if (File.Exists(tmpFile)) { File.Delete(tmpFile); } } catch (System.Exception e) { ed.WriteMessage("\nErreur: {0}\n{1}", e.Message, e.StackTrace); } } // Command [CommandMethod("PublishToDwf")] public void PublishToDwf() { short bgp = (short)AcAp.GetSystemVariable("BACKGROUNDPLOT"); AcAp.SetSystemVariable("BACKGROUNDPLOT", 0); CreateDSD(); Publish(); Cleanup(); AcAp.SetSystemVariable("BACKGROUNDPLOT", bgp); } } }
The upper code is a quick (and dirty) adaptation of the one I used to plot layouts to a PDF file.
Publishing a 3d DWF may be a little more simple (removing unsefull lines).
Here's a little class you can instanciate to call the Publish() method:
Dim plot3d As New PlotTo3dDwf("C:\Temp") plot3d.Publish()
C#
using System.IO; using System.Text; using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.PlottingServices; namespace Plottings { public class PlotTo3dDwf { private string dwgFile, dwfFile, dsdFile, title, outputDir; public PlotTo3dDwf() { outputDir = (string)Application.GetSystemVariable("DWGPREFIX"); string name = (string)Application.GetSystemVariable("DWGNAME"); dwgFile = Path.Combine(outputDir, name); title = Path.GetFileNameWithoutExtension(name); dwfFile = Path.ChangeExtension(dwgFile, "dwf"); dsdFile = Path.ChangeExtension(dwfFile, ".dsd"); } public PlotTo3dDwf(string outputDir) : this () { this.outputDir = outputDir; } public void Publish() { short bgPlot = (short)Application.GetSystemVariable("BACKGROUNDPLOT"); Application.SetSystemVariable("BACKGROUNDPLOT", 0); if (!Directory.Exists(outputDir)) Directory.CreateDirectory(outputDir); using (DsdData dsd = new DsdData()) using (DsdEntryCollection dsdEntries = new DsdEntryCollection()) { // add the Model layout to the entry collection DsdEntry dsdEntry = new DsdEntry(); dsdEntry.DwgName = dwgFile; dsdEntry.Layout = "Model"; dsdEntry.Title = title; dsdEntry.Nps = "0"; dsdEntries.Add(dsdEntry); dsd.SetDsdEntryCollection(dsdEntries); // set DsdData dsd.Dwf3dOptions.PublishWithMaterials = true; dsd.Dwf3dOptions.GroupByXrefHierarchy = true; dsd.SetUnrecognizedData("PwdProtectPublishedDWF", "FALSE"); dsd.SetUnrecognizedData("PromptForPwd", "FALSE"); dsd.SheetType = SheetType.SingleDwf; dsd.NoOfCopies = 1; dsd.ProjectPath = outputDir; dsd.IsHomogeneous = true; if (File.Exists(dsdFile)) File.Delete(dsdFile); // write the DsdData file dsd.WriteDsd(dsdFile); // get the Dsd File contents string str; using (StreamReader sr = new StreamReader(dsdFile, Encoding.Default)) { str = sr.ReadToEnd(); } // edit the contents str = str.Replace("Has3DDWF=0", "Has3DDWF=1"); str = str.Replace("PromptForDwfName=TRUE", "PromptForDwfName=FALSE"); // rewrite the Dsd file using (StreamWriter sw = new StreamWriter(dsdFile, false, Encoding.Default)) { sw.Write(str); } // import the Dsd file contents in the DsdData dsd.ReadDsd(dsdFile); File.Delete(dsdFile); PlotConfig pc = PlotConfigManager.SetCurrentConfig("DWF6 ePlot.pc3"); Application.Publisher.PublishExecute(dsd, pc); Application.SetSystemVariable("BACKGROUNDPLOT", bgPlot); } } } }
VB
Imports System.IO Imports System.Text Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.PlottingServices Namespace Plottings Public Class PlotTo3dDwf Private dwgFile, dwfFile, dsdFile, title, outputDir As String Public Sub New() outputDir = DirectCast(Application.GetSystemVariable("DWGPREFIX"), String) Dim name As String = DirectCast(Application.GetSystemVariable("DWGNAME"), String) dwgFile = Path.Combine(outputDir, name) title = Path.GetFileNameWithoutExtension(name) dwfFile = Path.ChangeExtension(dwgFile, "dwf") dsdFile = Path.ChangeExtension(dwfFile, ".dsd") End Sub Public Sub New(outputDir As String) Me.New() Me.outputDir = outputDir End Sub Public Sub Publish() Dim bgPlot As Short = CShort(Application.GetSystemVariable("BACKGROUNDPLOT")) Application.SetSystemVariable("BACKGROUNDPLOT", 0) If Not Directory.Exists(outputDir) Then Directory.CreateDirectory(outputDir) End If Using dsd As New DsdData() Using dsdEntries As New DsdEntryCollection() ' add the Model layout to the entry collection Dim dsdEntry As New DsdEntry() dsdEntry.DwgName = dwgFile dsdEntry.Layout = "Model" dsdEntry.Title = title dsdEntry.Nps = "0" dsdEntries.Add(dsdEntry) dsd.SetDsdEntryCollection(dsdEntries) ' set DsdData data dsd.Dwf3dOptions.PublishWithMaterials = True dsd.Dwf3dOptions.GroupByXrefHierarchy = True dsd.SetUnrecognizedData("PwdProtectPublishedDWF", "FALSE") dsd.SetUnrecognizedData("PromptForPwd", "FALSE") dsd.SheetType = SheetType.SingleDwf dsd.NoOfCopies = 1 dsd.ProjectPath = outputDir dsd.IsHomogeneous = True If File.Exists(dsdFile) Then File.Delete(dsdFile) End If ' write the DsdData file dsd.WriteDsd(dsdFile) ' get the Dsd File contents Dim str As String Using sr As New StreamReader(dsdFile, Encoding.[Default]) str = sr.ReadToEnd() End Using ' edit the contents str = str.Replace("Has3DDWF=0", "Has3DDWF=1") str = str.Replace("PromptForDwfName=TRUE", "PromptForDwfName=FALSE") ' rewrite the Dsd file Using sw As New StreamWriter(dsdFile, False, Encoding.[Default]) sw.Write(str) End Using ' import the Dsd file new contents in the DsdData dsd.ReadDsd(dsdFile) File.Delete(dsdFile) Dim pc As PlotConfig = PlotConfigManager.SetCurrentConfig("DWF6 ePlot.pc3") Application.Publisher.PublishExecute(dsd, pc) Application.SetSystemVariable("BACKGROUNDPLOT", bgPlot) End Using End Using End Sub End Class End Namespace
_gile, thanks for the code! I will try this when I get time later this week.
Ken
_gile, I got a chance to try your second set of code this morning, and it appears to work, as far as creating a dwf file. However, the dwf file it creates I can't open (see attached) - it hangs up after starting to open. I'm using Map 3D 2013. Note that I can create 3DDWF from the command line (so I know that the drivers are there and working - unless this uses something different).
Also, I'm not familiar with working with DSD files and have the following questions:
1. I want the 3D DWF file to have a different name than the drawing (as I will already have a 2D DWF file in the folder) - somthing like Drawingname-3D.dwf. So where would I change that? I tried changing the "name" variable and the "dwfFile" variable, but neither worked (i.e. it didn't create the file).
2. Since the folder that I'm creating the new 3D DWF file in may already have an existing (older) 3D DWF, I want to overwrite the older file. While I can write something to check for the file and delete it, I was wondering if there was something in your Publish() code section that could force an overwrite and supress any dialog boxes (that ask you if you want to overwrite the file).
Thanks again for your help on this.
Ken
I can open your 3d DWF file, but it looks like empty, I can't say why.
1. Try this in the constructor :
dwfFile = Path.Combine(outputDir, title & "-3d.dwf")
2. Add this at the begining of the Publish() code:
If File.Exists(dwfFile) Then File.Delete(dwfFile) End If
_gile, thanks for the suggestions. I just tried Publish within Autocad and I get the same results (i.e. the dwf is blank). However, 3DDWF does work. I think I had the problem with both Publish and 3DDWF not working when I first installed Map 3D 2013 and got 3DDWF working after re-installing. I will try a reinstall to see if I can get that piece working.
Otherwise, I think your code works fine.
Thanks again for your help!
Ken
_gile, one more question. I have everything working (the reinstall worked on the Publish command), except the naming (i.e. to drawingname-3D.dwf). I don't see where in the Publish sub where it actually uses the dwfFile variable. I see that it uses the dwgFile variable, but not the dwfFile variable.
Thanks,
Ken
Oopss !...
i removed a DsdData setting I shouldn't: DsdData.DestinationName. This isn't required while DsdData.SheetType = SheetType.SingleDwf (this forces the output file name to be the same as the input dwg).
Here's a VB code which seems to work as you expect:
Imports System.IO Imports System.Text Imports Autodesk.AutoCAD.ApplicationServices Imports Autodesk.AutoCAD.PlottingServices Namespace Plottings Public Class PlotTo3dDwf Private dwgFile, dwfFile, dsdFile, title, outputDir As String Public Sub New() outputDir = DirectCast(Application.GetSystemVariable("DWGPREFIX"), String) Dim name As String = DirectCast(Application.GetSystemVariable("DWGNAME"), String) dwgFile = Path.Combine(outputDir, name) title = Path.GetFileNameWithoutExtension(name) dwfFile = Path.Combine(outputDir, title & "-3d.dwf") ' <- add the "-3d" suffix to the file name dsdFile = Path.ChangeExtension(dwfFile, ".dsd") End Sub Public Sub New(outputDir As String) Me.New() Me.outputDir = outputDir dwfFile = Path.Combine(outputDir, title & "-3d.dwf") End Sub Public Sub Publish() Dim bgPlot As Short = CShort(Application.GetSystemVariable("BACKGROUNDPLOT")) Application.SetSystemVariable("BACKGROUNDPLOT", 0) Try If Not Directory.Exists(outputDir) Then Directory.CreateDirectory(outputDir) End If Using dsd As New DsdData() Using dsdEntries As New DsdEntryCollection() ' add the Model layout to the entry collection Dim dsdEntry As New DsdEntry() dsdEntry.DwgName = dwgFile dsdEntry.Layout = "Model" dsdEntry.Title = title dsdEntry.Nps = "0" dsdEntries.Add(dsdEntry) dsd.SetDsdEntryCollection(dsdEntries) ' set DsdData data dsd.Dwf3dOptions.PublishWithMaterials = True dsd.Dwf3dOptions.GroupByXrefHierarchy = True dsd.SetUnrecognizedData("PwdProtectPublishedDWF", "FALSE") dsd.SetUnrecognizedData("PromptForPwd", "FALSE") dsd.SheetType = SheetType.MultiDwf dsd.NoOfCopies = 1 dsd.ProjectPath = outputDir dsd.DestinationName = dwfFile dsd.IsHomogeneous = True If File.Exists(dsdFile) Then File.Delete(dsdFile) End If ' write the DsdData file dsd.WriteDsd(dsdFile) ' get the Dsd File contents Dim str As String Using sr As New StreamReader(dsdFile, Encoding.[Default]) str = sr.ReadToEnd() End Using ' edit the contents str = str.Replace("Has3DDWF=0", "Has3DDWF=1") str = str.Replace("PromptForDwfName=TRUE", "PromptForDwfName=FALSE") ' rewrite the Dsd file Using sw As New StreamWriter(dsdFile, False, Encoding.[Default]) sw.Write(str) End Using ' import the Dsd file new contents in the DsdData dsd.ReadDsd(dsdFile) File.Delete(dsdFile) Dim pc As PlotConfig = PlotConfigManager.SetCurrentConfig("DWF6 ePlot.pc3") Application.Publisher.PublishExecute(dsd, pc) End Using End Using Finally Application.SetSystemVariable("BACKGROUNDPLOT", bgPlot) End Try End Sub End Class End Namespace
_gile, Thanks for the update! I'm still having issues, but I'm thinking it is something with my drawings or system. I ran it on four drawings yesterday and it created dwf files for two of them, but not the other two. Of the two it created, one was blank and one was ok. So I'll research this more on my end, but I think your code is working correctly.
Thanks again!
Ken