乐筑天下

搜索
欢迎各位开发者和用户入驻本平台 尊重版权,从我做起,拒绝盗版,拒绝倒卖 签到、发布资源、邀请好友注册,可以获得银币 请注意保管好自己的密码,避免账户资金被盗
查看: 173|回复: 13

.NET Layout,ViewPort,Plot Routines

[复制链接]

116

主题

996

帖子

9

银币

顶梁支柱

Rank: 50Rank: 50

铜币
1466
发表于 2010-1-28 06:39:35 | 显示全部楼层 |阅读模式
LIBRARY THREAD for  AutoCAD Layout,ViewPort,Plot
Members are encouraged to post any functions, methods, snips regarding
AutoCAD Layout,ViewPort,Plot in .NET : C# ,  VB , F# , Python , etc
Feel free to include comments, descriptive notes, limitations,  and images to document your post.
Please post questions in a regular thread.
回复

使用道具 举报

28

主题

249

帖子

7

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
361
发表于 2010-1-28 11:01:03 | 显示全部楼层
Here is the link to my batch plot routine that I did in C#.
[  ]
回复

使用道具 举报

14

主题

275

帖子

6

银币

后起之秀

Rank: 20Rank: 20Rank: 20Rank: 20

铜币
331
发表于 2010-1-31 08:15:06 | 显示全部楼层
  1.     ' A function to return the current Layout, you can get properties as name and id from the returned object.
  2.     ' Ex: hzGetCurrentLayout.Name
  3.     ' To check if the current layout is Modelspace, use .modeltype as property (true is Model, false is Paper).
  4.     Shared Function hzGetCurrentLayout() As Layout
  5.       '' Get the current document and database, and start a transaction
  6.       Dim acDoc As Document = Application.DocumentManager.MdiActiveDocument
  7.       Dim acCurDb As Database = acDoc.Database
  8.       Dim acLayoutMgr As LayoutManager
  9.       Dim acLayout As Layout
  10.       Using acTrans As Transaction = acCurDb.TransactionManager.StartTransaction()
  11.         ' Reference the Layout Manager
  12.         acLayoutMgr = LayoutManager.Current
  13.         ' Get the current layout
  14.         acLayout = acTrans.GetObject(acLayoutMgr.GetLayoutId(acLayoutMgr.CurrentLayout), OpenMode.ForRead)
  15.         ' Close transaction
  16.         acTrans.Dispose()
  17.       End Using
  18.       Return acLayout
  19.     End Function

It should be possible to get this information also via a variable.
回复

使用道具 举报

15

主题

687

帖子

169

银币

中流砥柱

Rank: 25

铜币
582
发表于 2012-7-15 09:56:43 | 显示全部楼层
Publishing to 3d DWF
C#
[ol]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);
            try
            {
                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 new contents in the DsdData
                    dsd.ReadDsd(dsdFile);

                    File.Delete(dsdFile);

                    PlotConfig pc = PlotConfigManager.SetCurrentConfig("DWF6 ePlot.pc3");
                    Application.Publisher.PublishExecute(dsd, pc);
                }
            }
            finally
            {
                Application.SetSystemVariable("BACKGROUNDPLOT", bgPlot);
            }
        }
    }
}
[/ol]
VB
[ol]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)
            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.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)
                    End Using
                End Using
            Finally
                Application.SetSystemVariable("BACKGROUNDPLOT", bgPlot)
            End Try
        End Sub
    End Class
End Namespace[/ol]
回复

使用道具 举报

2

主题

31

帖子

1

银币

初来乍到

Rank: 1

铜币
39
发表于 2012-7-15 18:50:24 | 显示全部楼层

Great work.
Just one small comment (and some code), which is that just like we've been doing in LISP since the beginning, we need to not allow a changed system variable's value to remain changed when our command exits. Using your code as an example, if an exception caused the code to exit before the BACKGROUNDPLOT system variable's value was restored, it will remain set to the temporary value you assign it to. While in many cases it may not be an issue, you might note that there are quite a few posts by users asking why the values of certain system variables mysteriously change while using AutoCAD, and of course, it is almost always caused by scripting that fails to take the needed precautions.
Here's a solution I've been using for quite some time, that I've recently updated to support System.Dynamic.
[ol]
// LocalSystemVariables.cs  copyright (c) 2007-2012  Tony Tanzillo

using System;
using System.Linq;
using System.Dynamic;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Autodesk.AutoCAD.ApplicationServices;

namespace Autodesk.AutoCAD.ApplicationServices
{
  // A common problem that affects AutoCAD scripting
  // using LISP, is the need to temporarily change
  // the values of AutoCAD system variables, and save
  // and restore their previous values once the code
  // that requires the values changed has finished.
  //
  // At first this seems like a simple problem because
  // the programmer assumes that they only need to save
  // the previous values of system variables in local or
  // global program variables, change the system variable
  // values, and just before their code has finished its
  // job, restore the system variables to their previous,
  // saved values.
  //
  // What complicates this seemingly-simple task, and causes
  // significant problems for users, is that when an error
  // causes a script to terminate prematurely, unless there
  // are special precautions taken by an error handler, the
  // values of changed system variables will not be restored
  // to their previous, user-assigned values. In fact, this
  // is a well-known problem in the world of LISP scripting,
  // and many strategies have been devised and published to
  // deal with it.
  //
  // In the .NET world, the problem is no less prominent, and
  // failure to address it can result in the very same problem
  // for users (the values of system variables changed after a
  // .NET program or custom command has exited, usually as a
  // result of an error).
  //
  // Because error/exception handling is far more robust in
  // the .NET world (in contrast to LISP), the means we have
  // to deal with the problem can also be more robust.  
  //
  // LocalSystemVariable class.
  //
  // Encapsulates an AutoCAD system variable and an
  // associated value that has the same scope as the
  // life of the LocalSystemVariable instance.
  //
  // This class can be used to temporarily change the
  // value of a system variable, save the previous value,
  // and ensure the saved value is properly restored
  // when the LocalSystemVariable instance is disposed.
  
  // To use this class, create an instance of it under
  // control of a using() directive, and supply the name
  // and the new, temporary value for the system variable.
  //
  // within the using() block, the system variable's value
  // will be set to the value passed to the constructor.
  // When control leaves the using() block, the previous
  // saved value of the system variable (the value it had
  // when the constructor was called) will be restored.
  //
  // This very simple example shows how to temporarily
  // set the value of the OSMODE system variable to 0
  // for the duration of a registered command handler:

  public static class LocalSystemVariableExample
  {
    [CommandMethod("MYCOMMAND")]
    public static void MyCommand()
    {
      using( var osmode = new LocalSystemVariable( "OSMODE", 0 ) )
      {
        // here, the value of the OSMODE system variable
        // will be set to 0.  When the using() block is
        // exited (even if it happens as a result of an
        // exception), the value of OSMODE is restored
        // to the value it had prior to entering this
        // using() block.
        
        // Show the temporary value of OSMODE:
        
        WriteMessage("In MyCommand(): The value of OSMODE is now {0}", osmode.Value );
      }
      
      // Show the restored value of OSMODE:
      
      WriteMessage("Exiting MyCommand(): the value of OSMODE is now {0}",
        Application.GetSystemVariable("OSMODE") );
      
    }
   
    // Example usage of LocalSystemVariables collection
    // to manage multiple system varibles with temporary
    // values within the same scope.
   
    // Just as when driving AutoCAD from LISP using the
    // (command) function, When doing the same in .NET
    // via the acedCmd() method, it is often necessary
    // to save, change, and then restore the values of
    // several system variables. This example shows how
    // that can be easily achieved through the use of
    // the LocalSystemVariables class:
   
    [CommandMethod("MYCOMMAND2")]
    public static void MyCommand2()
    {
      // Prompt for user input here
      
      using( var sysvars = new LocalSystemVariables() )
      {
        sysvars["CMDECHO"] = 0;
        sysvars["HIGHLIGHT"] = 0;
        sysvars["BLIPMODE"] = 0;
        sysvars["OSMODE"] = 0;
        
        // Make calls to acedCmd() here to perform
        // operations using AutoCAD commands.
        
        
      } // At this point the previous, saved values of all
        // system variables changed above are automatically
        // restored, even if an exception causes control flow
        // to exit the using() block prematurely.

    }
   
    // This example is functionally identical to the above
    // one, except that it uses System.Dynamic to specify
    // the names of the system variable as code identifiers,
    // as if they were properties of the LocalSystemVariables
    // class (note that identifiers are case-insensitive):
   
    [CommandMethod("MYCOMMAND3")]
    public static void MyCommand3()
    {
      // Prompt for user input here
      
      using( dynamic sysvars = new LocalSystemVariables() )
      {
        sysvars.CmdEcho = 0;
        sysvars.Highlight = 0;
        sysvars.BlipMode = 0;
        sysvars.OSMode = 0;
        
        // Make calls to acedCmd() here to perform
        // operations using AutoCAD commands.
        
      } // Saved system variable values restored here
    }
   
    public static void WriteMessage( string fmt, params object[] args )
    {
      Application.DocumentManager.MdiActiveDocument.Editor.WriteMessage( fmt, args );
    }
  }
  
  // LocalSystemVariable class
  
  public class LocalSystemVariable : IDisposable
  {
    object oldval = null;
    string name = string.Empty;
   
    public LocalSystemVariable( string name, object newval )
    {
      this.name = name;
      this.oldval = SetValue( name, newval );
    }

    public string Name {get { return this.name; } }

    internal static object GetValue( string name, bool validate = false )
    {
      if( string.IsNullOrEmpty( name ) )
        throw new ArgumentException("name");
      try
      {
        object result = Application.GetSystemVariable( name );
        if( result == null )
          throw new ArgumentException("name");
        return result;
      }
      catch
      {
        if( validate )
          throw new ArgumentException(
            string.Format( "Invalid System Variable Name: {0}", name ));
        else
          return null;
      }
    }

    // This was revised to deal with incompatible types
    // (e.g., passing an int when a short is required),
    // and will try to convert the new value to the type
    // of the existing value, although I suspect that the
    // managed runtime is already converting int to short
    // in all cases.
   
    internal static object SetValue( string name, object value )
    {
      if( value == null )
        throw new ArgumentNullException( "value" );
      object oldval = GetValue( name, true );
      object newval = value;
      if( oldval.GetType() != value.GetType() )
        newval = Convert.ChangeType( value, oldval.GetType() );
      if( ! object.Equals( newval, oldval ) )
        Application.SetSystemVariable( name, newval );
      return oldval;
    }

    // Get or set the current value of the system variable.
    // Note that setting this property does not change the
    // initial saved value that will be restored when the
    // instance is disposed:
   
    public object Value
    {
      get
      {
        return GetValue( this.name, true );
      }
      set
      {
        SetValue( this.name, value );
      }
    }

    public void Dispose()
    {
      if( oldval != null )
      {
        try
        {
          SetValue( this.name, this.oldval );
        }
        finally
        {
          this.oldval = null;
        }
      }
    }
  }
  
  // A collection of LocalSystemVariables that automatically
  // disposes its elements when the collection is disposed.
  //
  // This class can be used to manage multiple LocalSystemVariable
  // instances without the complexity that would otherwise result
  // from using multiple instances of LocalSystemVariables directly.
  //
  // The contained system variables can be accessed and added via
  // the default indexer, or by declaring the instance as 'dynamic',
  // and writing the system variable names as identifiers (as if
  // they were properties of this class).
  //
  // Refer to the included examples for both forms of usage.
  
  public class LocalSystemVariables : DynamicObject, IDisposable, IEnumerable
  {
    Collection items = new Collection();
  
    public LocalSystemVariables()
    {
    }
   
    public bool Contains( string name )
    {
      return items.Contains( name );
    }
   
    public override bool TryGetMember( GetMemberBinder binder, out object result )
    {
      result = LocalSystemVariable.GetValue( binder.Name );
      return result != null;
    }
   
    public override bool TrySetMember( SetMemberBinder binder, object value )
    {
      this[binder.Name] = value;
      return true;
    }
   
    public object this[string name]
    {
      get
      {
        return LocalSystemVariable.GetValue( name, true );
      }
      set
      {
        if( ! items.Contains( name ) )
          items.Add( new LocalSystemVariable( name, value ) );
        else
          LocalSystemVariable.SetValue( name, value );
      }
    }
   
    public void Remove( string name )
    {
      items.Remove( name );
    }

    public void Clear()
    {
      items.Clear();
    }
   
    public int Count
    {
      get
      {
        return items.Count;
      }
    }
   
    public void Dispose()
    {
      if( items != null )
      {
        try
        {
          using( IEnumerator e = items.Reverse().GetEnumerator() )
          {
            DisposeNext( e );
          }
        }
        finally
        {
          items = null;
        }
      }
    }
   
    // Recursively dispose each item in a try/finally block
    // to ensure that all items are disposed. This could be
    // viewed as being very dangerous, but because the number
    // of elements is always small, the risk of overflowing
    // the stack would be virtually impossible.
   
    void DisposeNext( IEnumerator e )
    {
      if( e.MoveNext() )
      {
        try
        {
          e.Current.Dispose();
        }
        finally
        {
          DisposeNext( e );
        }
      }
    }
   
    public IEnumerator GetEnumerator()
    {
      return items.GetEnumerator();
    }
   
    IEnumerator IEnumerable.GetEnumerator()
    {
      return this.GetEnumerator();
    }
  
    class Collection : KeyedCollection
    {
      public Collection() : base( StringComparer.OrdinalIgnoreCase )
      {
      }
      
      protected override string GetKeyForItem( LocalSystemVariable value )
      {
        return value.Name.ToUpper();
      }
    }
  }  

}

[/ol]
kdub:edit code=csharp
回复

使用道具 举报

15

主题

687

帖子

169

银币

中流砥柱

Rank: 25

铜币
582
发表于 2012-7-16 02:27:15 | 显示全部楼层
Thanks, Tony.
You're absolutely right.
I should have used a try/finally block to reset BACKGROUNDPLOT
Your 'disposable' Local System Variables class is amazing. I enjoy it as I enjoyed the 'ai-sysvar' LISP function when I discovered it.
To follow .
回复

使用道具 举报

2

主题

31

帖子

1

银币

初来乍到

Rank: 1

铜币
39
发表于 2012-7-19 02:49:53 | 显示全部楼层
And now for some relatively-legitimate nit-picking (of my own code).
In the above code, the LocalSystemVariables class uses a scheme that attempts to ensure that every element in the collection is disposed, even if one or more of their Dispose() implementations throws an exception.  
While the scheme works, it is unnecessarily stack-intensive, recursing one level for every element in the list (and as I mentioned in my comments, a stack overflow would be extremely unlikely).
This version of DisposeNext() will only recurse into itself if a call to Dispose() throws an exception:
[ol]
    // LocalSysemVariables.DisposeNext() revised:
    // This revised version of DisposeNext() is only recursive if an
    // element's Dispose() implementation throws an exception, and
    // limits the depth of recursion to the number of elements whose
    // Dispose() throws an exception:

    void DisposeNext( IEnumerator[I] e )
    {
      while( e.MoveNext() )
      {
        try
        {
          e.Current.Dispose();
        }
        catch
        {
          DisposeNext( e );
          throw;
        }
      }
    }

[/ol]
One more comment, which is why a class derived from KeyedCollection was used rather than a Dictionary. Aside from the fact that KeyedCollection is an ordered collection, it also uses a hybrid algorithm for storage and lookup. When the number of elements in the collection is small, it stores them in a list and uses a simple linear search for lookups, which can be faster than a Dictionary when the number of items is below a certain threshold. Once the number of elements grows beyond the threshold, the items are stored in, and retrieved from a Dictionary, which is faster with a larger number of items.
kdub:edit code=csharp
回复

使用道具 举报

15

主题

687

帖子

169

银币

中流砥柱

Rank: 25

铜币
582
发表于 2012-10-6 03:46:49 | 显示全部楼层
Thanks again Tony for sharing, really valuable.
I have an error in one line as follows:
368: IEnumerator IEnumerable.GetEnumerator()
Using the generic type 'System.Collections.Generic.IEnumerator' requires 1 type arguments
Been unable to resolve unfortunately, have I missed something?
Regards, Dale
回复

使用道具 举报

15

主题

687

帖子

169

银币

中流砥柱

Rank: 25

铜币
582
发表于 2012-10-6 04:00:20 | 显示全部楼层
While you wait for Tony to reply, try adding
  using System.Collections;
回复

使用道具 举报

44

主题

3166

帖子

2803

银币

中流砥柱

Rank: 25

铜币
557
发表于 2012-10-6 08:22:14 | 显示全部楼层
Just returned to say exactly that. Dumb me...
Thanks,
Dale
回复

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

  • 微信公众平台

  • 扫描访问手机版

  • 点击图片下载手机App

QQ|关于我们|小黑屋|乐筑天下 繁体中文

GMT+8, 2025-2-5 09:35 , Processed in 0.627213 second(s), 72 queries .

© 2020-2025 乐筑天下

联系客服 关注微信 帮助中心 下载APP 返回顶部 返回列表