乐筑天下

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

Kean专题(3)—Graphics_System

[复制链接]

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 10:24:00 | 显示全部楼层 |阅读模式
原帖:
一、使用NetApi渲染Cad模型
April 05, 2007
Rendering  models offscreen using .NET
这个问题是在内部讨论,我想分享的代码提供了我们的技术团队与您(当然我们有一些小的补充)。
This question came up in an internal discussion, and I thought I'd share the code provided by our Engineering team with you (with a few minor additions from my side, of course).
这个想法是提供一个三维场景离屏(即保存到文件所提供的不可见的图像编辑器) 。The idea is to render a 3D scene off-screen (i.e. save to file the rendered image not visible in the editor). In the below code, we do zoom to the extents of the 3D model that gets created, just to show it's there, but the rendering activity itself is not performed by the 3D view that is used to generate the graphics for AutoCAD's editor window.
A 3D model does need to be loaded in the editor for this to work, so I decided to add a simple sphere to the modelspace and set its material to one that renders nicely (Sitework.Paving - Surfacing.Riverstone.Mortared). The code doesn't import the material programmatically, so you'll want to make sure it's there in the drawing to get the full effect of the rendering (by dragging the material into the drawing view from the materials tool palette, for instance), or to change the code to point to one that exists in the active drawing.
Here's the C# code:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.GraphicsSystem;
  6. using Autodesk.AutoCAD.Interop;
  7. using System.Drawing;namespace OffscreenRendering
  8. {
  9.   public class Commands
  10.   {
  11.     [CommandMethod("OSR")]
  12.     static public void OffscreenRender()
  13.     {
  14.       CreateSphere();
  15.       RenderToFile("c:\\sphere.png");
  16.     }    static public void CreateSphere()
  17.     {
  18.       Document doc =
  19.         Application.DocumentManager.MdiActiveDocument;
  20.       Database db = doc.Database;
  21.       Editor ed = doc.Editor;      Transaction tr =
  22.         doc.TransactionManager.StartTransaction();
  23.       using (tr)
  24.       {
  25.         BlockTable bt =
  26.           (BlockTable)tr.GetObject(
  27.             db.BlockTableId,
  28.             OpenMode.ForRead
  29.           );
  30.         BlockTableRecord btr =
  31.           (BlockTableRecord)tr.GetObject(
  32.             bt[BlockTableRecord.ModelSpace],
  33.             OpenMode.ForWrite
  34.           );
  35.         Solid3d sol = new Solid3d();
  36.         sol.CreateSphere(10.0);        const string matname =
  37.           "Sitework.Paving - Surfacing.Riverstone.Mortared";
  38.         DBDictionary matdict =
  39.           (DBDictionary)tr.GetObject(
  40.             db.MaterialDictionaryId,
  41.             OpenMode.ForRead
  42.           );
  43.         if (matdict.Contains(matname))
  44.         {
  45.           sol.Material = matname;
  46.         }
  47.         else
  48.         {
  49.           ed.WriteMessage(
  50.             "\nMaterial (" + matname + ") not found" +
  51.             " - sphere will be rendered without it.",
  52.             matname
  53.           );
  54.         }
  55.         btr.AppendEntity(sol);        tr.AddNewlyCreatedDBObject(sol, true);
  56.         tr.Commit();
  57.       }
  58.       AcadApplication acadApp =
  59.         (AcadApplication)Application.AcadApplication;
  60.       acadApp.ZoomExtents();
  61.     }    static public void RenderToFile(string filename)
  62.     {
  63.       Document doc =
  64.         Application.DocumentManager.MdiActiveDocument;
  65.       Editor ed = doc.Editor;
  66.       int vpn =
  67.         System.Convert.ToInt32(
  68.           Application.GetSystemVariable("CVPORT")
  69.         );
  70.       View gsv =
  71.         doc.GraphicsManager.GetGsView(vpn, true);
  72.       using (View view = gsv.Clone(true, true))
  73.       {
  74.         Device dev =
  75.           doc.GraphicsManager.CreateAutoCADOffScreenDevice();
  76.         using (dev)
  77.         {
  78.           dev.OnSize(doc.GraphicsManager.DisplaySize);
  79.           dev.DeviceRenderType = RendererType.FullRender;
  80.           dev.Add(view);
  81.           using (Bitmap bitmap = view.RenderToImage())
  82.           {
  83.             bitmap.Save(filename);
  84.             ed.WriteMessage(
  85.               "\nRendered image saved to: " +
  86.               filename
  87.             );
  88.           }
  89.         }
  90.       }
  91.     }
  92.   }
  93. }
And here's the resized contents of the file created at c:\sphere.png by the OSR command:

yz3uwc0hmqc.png

yz3uwc0hmqc.png

本帖以下内容被隐藏保护;需要你回复后,才能看到!

游客,如果您要查看本帖隐藏内容请回复
回复

使用道具 举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 10:46:00 | 显示全部楼层
二、模型快照
April 18, 2007
Taking a snapshot of the AutoCAD model (take 2)
In this previous post, we looked at some code to do a programmatic snapshot of AutoCAD's modelspace, saving the results to an image file.
From the discussion that followed, I realised that the code had an undesired (and unnecessary) side-effect of creating a new 3D GS View and leaving the modelspace with that view active. GS Views in AutoCAD 2007 have grey backgrounds by default, and so this change can be quite disturbing for users. The only reason we created the GS View in the first place (if one didn't already exist), was to use it to query the view position/target/up vector/field width and height and apply it to our new view. Thankfully it seems this can also be determined directly from the viewport.
So rather than calling GetGSView() and using the returned view to get that information, we now simply call SetViewFromViewport() specifying the viewport number held in CVPORT, and the graphics system manager for that document handles the rest.
Here's the updated C# code, which appears to achieve the same goals without the side-effect. Check line 124 for the new code, a few extraneous lines around it having been removed:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.GraphicsInterface;
  5. using Autodesk.AutoCAD.GraphicsSystem;
  6. using Autodesk.AutoCAD.Runtime;
  7. using Autodesk.AutoCAD.Interop;
  8. using System.Drawing;
  9. namespace OffscreenImageCreation
  10. {
  11.   public class Commands
  12.   {
  13.     [CommandMethod("OSS")]
  14.     static public void OffscreenSnapshot()
  15.     {
  16.       CreateSphere();
  17.       SnapshotToFile(
  18.         "c:\\sphere-Wireframe2D.png",
  19.         VisualStyleType.Wireframe2D
  20.       );
  21.       SnapshotToFile(
  22.         "c:\\sphere-Hidden.png",
  23.         VisualStyleType.Hidden
  24.       );
  25.       SnapshotToFile(
  26.         "c:\\sphere-Basic.png",
  27.         VisualStyleType.Basic
  28.       );
  29.       SnapshotToFile(
  30.         "c:\\sphere-ColorChange.png",
  31.         VisualStyleType.ColorChange
  32.       );
  33.       SnapshotToFile(
  34.         "c:\\sphere-Conceptual.png",
  35.         VisualStyleType.Conceptual
  36.       );
  37.       SnapshotToFile(
  38.         "c:\\sphere-Flat.png",
  39.         VisualStyleType.Flat
  40.       );
  41.       SnapshotToFile(
  42.         "c:\\sphere-Gouraud.png",
  43.         VisualStyleType.Gouraud
  44.       );
  45.       SnapshotToFile(
  46.         "c:\\sphere-Realistic.png",
  47.         VisualStyleType.Realistic
  48.       );
  49.     }
  50.     static public void CreateSphere()
  51.     {
  52.       Document doc =
  53.         Application.DocumentManager.MdiActiveDocument;
  54.       Database db = doc.Database;
  55.       Editor ed = doc.Editor;
  56.       Transaction tr =
  57.         doc.TransactionManager.StartTransaction();
  58.       using (tr)
  59.       {
  60.         BlockTable bt =
  61.           (BlockTable)tr.GetObject(
  62.             db.BlockTableId,
  63.             OpenMode.ForRead
  64.           );
  65.         BlockTableRecord btr =
  66.           (BlockTableRecord)tr.GetObject(
  67.             bt[BlockTableRecord.ModelSpace],
  68.             OpenMode.ForWrite
  69.           );
  70.         Solid3d sol = new Solid3d();
  71.         sol.CreateSphere(10.0);
  72.         const string matname =
  73.           "Sitework.Paving - Surfacing.Riverstone.Mortared";
  74.         DBDictionary matdict =
  75.           (DBDictionary)tr.GetObject(
  76.             db.MaterialDictionaryId,
  77.             OpenMode.ForRead
  78.           );
  79.         if (matdict.Contains(matname))
  80.         {
  81.           sol.Material = matname;
  82.         }
  83.         else
  84.         {
  85.           ed.WriteMessage(
  86.             "\nMaterial (" + matname + ") not found" +
  87.             " - sphere will be rendered without it.",
  88.             matname
  89.           );
  90.         }
  91.         btr.AppendEntity(sol);
  92.         tr.AddNewlyCreatedDBObject(sol, true);
  93.         tr.Commit();
  94.       }
  95.       AcadApplication acadApp =
  96.         (AcadApplication)Application.AcadApplication;
  97.       acadApp.ZoomExtents();
  98.     }
  99.     static public void SnapshotToFile(
  100.       string filename,
  101.       VisualStyleType vst
  102.     )
  103.     {
  104.       Document doc =
  105.         Application.DocumentManager.MdiActiveDocument;
  106.       Editor ed = doc.Editor;
  107.       Database db = doc.Database;
  108.       Manager gsm = doc.GraphicsManager;
  109.       // Get some AutoCAD system variables
  110.       int vpn =
  111.         System.Convert.ToInt32(
  112.           Application.GetSystemVariable("CVPORT")
  113.         );
  114.       using (View view = new View())
  115.       {
  116.         gsm.SetViewFromViewport(view, vpn);
  117.         // Set the visual style to the one passed in
  118.         view.VisualStyle = new VisualStyle(vst);
  119.         Device dev =
  120.           gsm.CreateAutoCADOffScreenDevice();
  121.         using (dev)
  122.         {
  123.           dev.OnSize(gsm.DisplaySize);
  124.           // Set the render type and the background color
  125.           dev.DeviceRenderType = RendererType.Default;
  126.           dev.BackgroundColor = Color.White;
  127.           // Add the view to the device and update it
  128.           dev.Add(view);
  129.           dev.Update();
  130.           using (Model model = gsm.CreateAutoCADModel())
  131.           {
  132.             Transaction tr =
  133.               db.TransactionManager.StartTransaction();
  134.             using (tr)
  135.             {
  136.               // Add the modelspace to the view
  137.               // It's a container but also a drawable
  138.               BlockTable bt =
  139.                 (BlockTable)tr.GetObject(
  140.                   db.BlockTableId,
  141.                   OpenMode.ForRead
  142.                 );
  143.               BlockTableRecord btr =
  144.                 (BlockTableRecord)tr.GetObject(
  145.                   bt[BlockTableRecord.ModelSpace],
  146.                   OpenMode.ForRead
  147.                 );
  148.               view.Add(btr, model);
  149.               tr.Commit();
  150.             }
  151.             // Take the snapshot
  152.             Rectangle rect = view.Viewport;
  153.             using (Bitmap bitmap = view.GetSnapshot(rect))
  154.             {
  155.               bitmap.Save(filename);
  156.               ed.WriteMessage(
  157.                 "\nSnapshot image saved to: " +
  158.                 filename
  159.               );
  160.               // Clean up
  161.               view.EraseAll();
  162.               dev.Erase(view);
  163.             }
  164.           }
  165.         }
  166.       }
  167.     }
  168.   }
  169. }
And here are the images created by the OSS command, listed by their visual style type...

wkjud5jaboi.png

wkjud5jaboi.png


回复

举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 10:50:00 | 显示全部楼层
三、使用Zoom
June 06, 2008
Zooming to a window or entity inside AutoCAD with .NET
This post was inspired by a recent email from Sreekar Devatha, who is just about to leave DevTech India to work in one of our Engineering teams in Singapore (all the best on your new adventure, Sreekar! :-).
It shows how to perform a programmatic zoom in .NET, whether to a window or to an entity. The .NET API in AutoCAD doesn't expose a handy "ZoomWindow" method, but there are a few options open that use officially supported APIs:
Create a ViewTableRecord and set it as the current view (the classic ObjectARX technique, as described in this DevNote on the ADN site)
Use the COM API to perform a ZoomWindow
Call the ZOOM command using one of the techniques in this previous post
The first two change the view very effectively, but don't show the nice view transitions you get with the ZOOM command (hence the 3rd option).
I ended up implementing the following C# code to show each of these techniques, which can be applied to commands that zoom either to a window (ZW) or to an entity (ZE). Just change the functions used from ZoomWin() to ZoomWin2() or ZoomWin3(), as needed:
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Runtime;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.Interop;
  7. namespace ZoomZoom
  8. {
  9.   public class Commands
  10.   {
  11.     // Zoom to a window specified by the user
  12.     [CommandMethod("ZW")]
  13.     static public void ZoomWindow()
  14.     {
  15.       Document doc =
  16.         Application.DocumentManager.MdiActiveDocument;
  17.       Database db = doc.Database;
  18.       Editor ed = doc.Editor;
  19.       // Get the window coordinates
  20.       PromptPointOptions ppo =
  21.         new PromptPointOptions(
  22.           "\nSpecify first corner:"
  23.         );
  24.       PromptPointResult ppr =
  25.         ed.GetPoint(ppo);
  26.       if (ppr.Status != PromptStatus.OK)
  27.         return;
  28.       Point3d min = ppr.Value;
  29.       PromptCornerOptions pco =
  30.         new PromptCornerOptions(
  31.           "\nSpecify opposite corner: ",
  32.           ppr.Value
  33.         );
  34.       ppr = ed.GetCorner(pco);
  35.       if (ppr.Status != PromptStatus.OK)
  36.         return;
  37.       Point3d max = ppr.Value;
  38.       // Call out helper function
  39.       // [Change this to ZoomWin2 or WoomWin3 to
  40.       // use different zoom techniques]
  41.       ZoomWin(ed, min, max);
  42.     }
  43.     // Zoom to the extents of an entity
  44.     [CommandMethod("ZE")]
  45.     static public void ZoomToEntity()
  46.     {
  47.       Document doc =
  48.         Application.DocumentManager.MdiActiveDocument;
  49.       Database db = doc.Database;
  50.       Editor ed = doc.Editor;
  51.       // Get the entity to which we'll zoom
  52.       PromptEntityOptions peo =
  53.         new PromptEntityOptions(
  54.           "\nSelect an entity:"
  55.         );
  56.       PromptEntityResult per = ed.GetEntity(peo);
  57.       if (per.Status != PromptStatus.OK)
  58.         return;
  59.       // Extract its extents
  60.       Extents3d ext;
  61.       Transaction tr =
  62.         db.TransactionManager.StartTransaction();
  63.       using (tr)
  64.       {
  65.         Entity ent =
  66.           (Entity)tr.GetObject(
  67.             per.ObjectId,
  68.             OpenMode.ForRead
  69.           );
  70.         ext =
  71.           ent.GeometricExtents;
  72.         tr.Commit();
  73.       }
  74.       ext.TransformBy(
  75.         ed.CurrentUserCoordinateSystem.Inverse()
  76.       );
  77.       // Call our helper function
  78.       // [Change this to ZoomWin2 or WoomWin3 to
  79.       // use different zoom techniques]
  80.       ZoomWin(ed, ext.MinPoint, ext.MaxPoint);
  81.     }
  82.     // Helper functions to zoom using different techniques
  83.     // Zoom using a view object
  84.     private static void ZoomWin(
  85.       Editor ed, Point3d min, Point3d max
  86.     )
  87.     {
  88.       Point2d min2d = new Point2d(min.X, min.Y);
  89.       Point2d max2d = new Point2d(max.X, max.Y);
  90.       ViewTableRecord view =
  91.         new ViewTableRecord();
  92.       view.CenterPoint =
  93.         min2d + ((max2d - min2d) / 2.0);
  94.       view.Height = max2d.Y - min2d.Y;
  95.       view.Width = max2d.X - min2d.X;
  96.       ed.SetCurrentView(view);
  97.     }
  98.     // Zoom via COM
  99.     private static void ZoomWin2(
  100.       Editor ed, Point3d min, Point3d max
  101.     )
  102.     {
  103.       AcadApplication app =
  104.         (AcadApplication)Application.AcadApplication;
  105.       double[] lower =
  106.         new double[3] { min.X, min.Y, min.Z };
  107.       double[] upper
  108.         = new double[3] { max.X, max.Y, max.Z };
  109.       app.ZoomWindow(lower, upper);
  110.     }
  111.     // Zoom by sending a command
  112.     private static void ZoomWin3(
  113.       Editor ed, Point3d min, Point3d max
  114.     )
  115.     {
  116.       string lower =
  117.         min.ToString().Substring(
  118.           1,
  119.           min.ToString().Length - 2
  120.         );
  121.       string upper =
  122.         max.ToString().Substring(
  123.           1,
  124.           max.ToString().Length - 2
  125.         );
  126.       string cmd =
  127.         "_.ZOOM _W " + lower + " " + upper + " ";
  128.       // Call the command synchronously using COM
  129.       AcadApplication app =
  130.         (AcadApplication)Application.AcadApplication;
  131.       app.ActiveDocument.SendCommand(cmd);
  132.       // Could also use async command calling:
  133.       //ed.Document.SendStringToExecute(
  134.       //  cmd, true, false, true
  135.       //);
  136.     }
  137.   }
  138. }
The code isn't as complete as I'd like: I haven't coded for all the view parameters (which are addressed in the DevNote quoted above in item 1, for those of you who are ADN members and can understand ObjectARX), and haven't tested for handling views not-aligned with the current UCS (etc., etc.). My main purpose was to outline the techniques, rather than to provide an exhaustive solution (and I'm currently on the train back from Geneva airport, having just flown to California and back for 3 days in the San Rafael office, which means any attempt on my side to make this exhaustive might end up exhausting me :-).
回复

举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 10:55:00 | 显示全部楼层
四、.Net版本的BlockView例子
June 13, 2008
AutoCAD .NET version of the ObjectARX BlockView sample
Fenton Webb, from DevTech Americas, has been beavering away on a .NET port of the ObjectARX BlockView sample (found on the ObjectARX SDK under samples/graphics/BlockView). Thanks, Fents! :-)
Here is the C# source project for Visual Studio 2005. To build it you will almost certainly need to remap the acdbmgd.dll and acmgd.dll assembly references in the project.
请点击此处下载

请先注册会员后在进行下载

已注册会员,请先登录后下载

文件名称:rehdlzz4nzp.zip 
下载次数:0  文件大小:150.65 KB  售价:2银币 [记录]
下载权限: 不限 以上或 Vip会员   [开通Vip]   [签到领银币]  [免费赚银币]


One important note: if you load this project and try to view the BlockViewDialog in the Visual Studio Designer, the Visual Studio application will almost certainly crash. This is because the Designer is attempting to load into the dialog the GsPreviewCtrl component which depends on AutoCAD (and therefore cannot be instantiated outside of the AutoCAD process). At least that's what appears to be happening.
To temporarily allow the dialog to load - so you can make changes to the dialog's menu, etc. - you will need to edit the C# code in the BlockViewDialog.Designer.cs file. There are two edits that are needed - one that declares a variable for the control (lines 650-651) and one that instantiates it (lines 107-108):
Comment out line 650 and uncomment line 651, so...
  650     private GsPreviewCtrl mPreviewCtrl;
  651     //private System.Windows.Forms.Panel mPreviewCtrl;
... becomes...
  650     //private GsPreviewCtrl mPreviewCtrl;
  651     private System.Windows.Forms.Panel mPreviewCtrl;
And do the same for lines 107 and 108, so...
  107       //this.mPreviewCtrl = new System.Windows.Forms.Panel();
  108       this.mPreviewCtrl = new GsPreviewCtrl();
... becomes...
  107       this.mPreviewCtrl = new System.Windows.Forms.Panel();
  108       //this.mPreviewCtrl = new GsPreviewCtrl();
Then the dialog should load properly in the Visual Studio Designer, with no crash (although you'll need to change the code back to the way it was to build the application, of course).
As for what the application does, here's the original sample's ReadMe, updated to reflect the new application's behaviour:
------------------------
Block View Sample Readme
------------------------
- NETLOAD the BlockView.NET.dll module
- Run command BView at the AutoCAD command line.
- Default operation is to display the current drawing using the current view settings of the current drawing.
Function Descriptions
---------------------
File->Open
Opens an existing drawing into the Block View dialog (by clearing the GraphicsSystem.View).
File->Output Image to Disk
Allows you to output a JPG;BMP;TIFFNG files as a snaphot of the current view shown in the BlockView dialog.
File->AcGsDevice Config
View or edit the current GraphicsSystem.Device configuration settings.
View->Zoom
Allows Zoom Extents/Zoom Window/Zoom In-Out functionality
View->Settings->Show
Allows the toggling of various GraphicsSystem.View settings such as Linetype/Material and Sectioning
View->Render Mode
Allows you to switch the rendering mode.
View->View Style
Allows you to change the view style of the GraphicsSystem.View. It has the same options as the SHADEMODE command.
Tools->ReMap Colors->Custom
Allows you to remap the color palette. This is particularily useful if you want to show a GraphicsSystem.View as a paperspace layout, with a white background. In this case you will need to remap white entities to appear in a different color.
Tools->ReMap Colors->Standard Colors
Restores the Color Palette back to the original one.
Tools->Add an Entity->To This Database
Adds an entity to the Model Space and adds to the GraphicsSystem.View.
Tools->Add an Entity->Temporary
Adds an entity just to the GraphicsSystem.View.
Here's a quick snapshot of the BlockView dialog with a conceptual view of the standard 3D view sample:

kkjh5sbv1av.png

kkjh5sbv1av.png

回复

举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 11:03:00 | 显示全部楼层
五、自定义捕捉模式
(实现对曲线1/4和3/4长的捕捉。)
October 31, 2008
Implementing a custom AutoCAD object snap mode using .NET
Thanks again to Augusto Gonçalves, from our DevTech Americas team, for providing the original VB.NET code for this sample, as well as helping investigate an issue I faced during implementation.
When I saw a recent reply to a developer, showing how to implement a custom object snap in AutoCAD using .NET, I had a really strong sense of nostalgia: it reminded me of a couple of early samples I contributed to the ObjectARX SDK: the "third" sample, which showed how to create a custom osnap that snapped to a third of the way along a curve, and "divisor" which generalised the approach to fractions of any size and was my first real attempt at using C++ templates. Ah, the memories. The samples were retired from this year's SDK, but were still included up to and including the ObjectARX SDK for AutoCAD 2008.
Anyway, the code Augusto sent was very familiar, and it turns out he based it on some documentation that was probably, in turn, based on my C++ sample. So it has come full circle. :-)
One thing I hadn't realised until I saw Augusto's email was that the ability to define custom object snaps had been exposed through .NET.
Here's the C# code that implements a new "quarter" object snap, which snaps to 1/4 and 3/4 along the length of a curve.[code]
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
[assembly:ExtensionApplication(
  typeof(OsnapApp.CustomOSnapApp))
]
namespace OsnapApp
{
  // Register and unregister custom osnap
  public class CustomOSnapApp : IExtensionApplication
  {
    private QuarterOsnapInfo _info =
      new QuarterOsnapInfo();
    private QuarterGlyph _glyph =
      new QuarterGlyph();
    private CustomObjectSnapMode _mode;
    public void Initialize()
    {
      // Register custom osnap on initialize
      _mode =
        new CustomObjectSnapMode(
          "Quarter",
          "Quarter",
          "Quarter of length",
          _glyph
        );
      // Which kind of entity will use the osnap
      _mode.ApplyToEntityType(
        RXObject.GetClass(typeof(Polyline)),
        new AddObjectSnapInfo(_info.SnapInfoPolyline)
      );
      _mode.ApplyToEntityType(
        RXObject.GetClass(typeof(Curve)),
        new AddObjectSnapInfo(_info.SnapInfoCurve)
      );
      _mode.ApplyToEntityType(
        RXObject.GetClass(typeof(Entity)),
        new AddObjectSnapInfo(_info.SnapInfoEntity)
      );
      // Activate the osnap
      CustomObjectSnapMode.Activate("_Quarter");
    }
    // Unregister custom osnap on terminate
    public void Terminate()
    {      
      CustomObjectSnapMode.Deactivate("_Quarter");
    }
  }
  // Create new quarter object snap
  public class QuarterGlyph : Glyph
  {
      private Point3d _pt;
      public override void SetLocation(Point3d point)
      {
        _pt = point;
      }
      public override void ViewportDraw(ViewportDraw vd)
      {
        int glyphPixels =
          CustomObjectSnapMode.GlyphSize;
        Point2d glyphSize =
          vd.Viewport.GetNumPixelsInUnitSquare(_pt);
        // Calculate the size of the glyph in WCS
        //  (use for text height factor)
        // We'll add 20% to the size, as otherwise
        //  it looks a little too small
        double glyphHeight =
          (glyphPixels / glyphSize.Y) * 1.2;
        string text = "¼";
        // Translate the X-axis of the DCS to WCS
        //  (for the text direction) and the snap
        //  point itself (for the text location)
        Matrix3d e2w = vd.Viewport.EyeToWorldTransform;
        Vector3d dir = Vector3d.XAxis.TransformBy(e2w);
        Point3d pt = _pt.TransformBy(e2w);
        //  Draw the centered text representing the glyph
        vd.Geometry.Text(
          pt,
          vd.Viewport.ViewDirection,
          dir,
          glyphHeight,
          1,
          0,
          text
        );
      }
  }
  // OSnap info
  public class QuarterOsnapInfo
  {
    public void SnapInfoEntity(
      ObjectSnapContext context,
      ObjectSnapInfo result)
    {
      // Nothing here
    }
    public void SnapInfoCurve(
      ObjectSnapContext context,
      ObjectSnapInfo result
    )
    {
      // For any curve
      Curve cv = context.PickedObject as Curve;
      if (cv == null)
        return;
      double startParam = cv.StartParam;
      double endParam = cv.EndParam;
      // Add osnap at first quarter
      double param =
        startParam + ((endParam - startParam) * 0.25);
      Point3d pt = cv.GetPointAtParameter(param);
      result.SnapPoints.Add(pt);
      // Add osnap at third quarter
      param =
        startParam + ((endParam - startParam) * 0.75);
      pt = cv.GetPointAtParameter(param);
      result.SnapPoints.Add(pt);
      if (cv.Closed)
      {
        pt = cv.StartPoint;
        result.SnapPoints.Add(pt);
      }
    }
    public void SnapInfoPolyline(
      ObjectSnapContext context,
      ObjectSnapInfo result)
    {
      // For polylines
      Polyline pl = context.PickedObject as Polyline;
      if (pl == null)
        return;
      // Get the overall start and end parameters
      double plStartParam = pl.StartParam;
      double plEndParam = pl.EndParam;
      // Get the local
      double startParam = plStartParam;
      double endParam = startParam + 1.0;
      while (endParam

tdnurl21erb.png

tdnurl21erb.png

回复

举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 11:12:00 | 显示全部楼层
六、在绘图界面动态显示坐标
见[]的相关例子之二
Drawing text planar to the screen inside AutoCAD's drawing window using .NET
回复

举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 11:30:00 | 显示全部楼层
七、在3D视图中变换视角
February 25, 2009
Smoothly transitioning between 3D AutoCAD views using .NET - Part 1
This inspiration for this post came during the research for this previous post, where we looked at implementing LookAt inside AutoCAD. It also has roots in the need to perform smooth transitions when zooming inside AutoCAD, which the ZOOM command manages for transitions between 2D views. Fenton Webb, from our DevTech Americas team, kindly volunteered to put together an ObjectARX sample that formed the basis for the code in this post. A huge thanks to Fents for his hard work on this!
This code presents a technique that allows smooth transitioning between 3D views in AutoCAD: you set up the parameters of the view to which you wish to change, and the function takes care of the heavy lifting. The technique follows more-or-less the same approach than that used to implement the ViewCube's smooth view transitions. It creates a GraphicsSystem.View object and manipulates it to transition smoothly to the new view.
Here's the C# code:
  1. using System;
  2. using System.Threading;
  3. using System.Drawing;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.EditorInput;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.Runtime;
  8. using Autodesk.AutoCAD.Geometry;
  9. using Autodesk.AutoCAD.GraphicsInterface;
  10. using Autodesk.AutoCAD.GraphicsSystem;
  11. using Autodesk.AutoCAD.Interop;
  12. namespace ViewTransitions
  13. {
  14.   public class MyView
  15.   {
  16.     public Point3d position;
  17.     public Point3d target;
  18.     public Vector3d upVector;
  19.     public double fieldWidth;
  20.     public double fieldHeight;
  21.     // Default constructor
  22.     public MyView(){}
  23.     // For constant defines below SWIso etc
  24.     public MyView(
  25.       double x1, double y1, double z1,
  26.       double x2, double y2, double z2,
  27.       double x3, double y3, double z3,
  28.       double x4, double y4
  29.     )
  30.     {
  31.       position = new Point3d(x1, y1, z1);
  32.       target = new Point3d(x2, y2, z2);
  33.       upVector = new Vector3d(x3, y3, z3);
  34.       fieldWidth = x4;
  35.       fieldHeight= y4;
  36.     }
  37.     public MyView(
  38.       Point3d position, Point3d target, Vector3d upVector,
  39.       double fieldWidth, double fieldHeight
  40.     )
  41.     {
  42.       this.position = position;
  43.       this.target = target;
  44.       this.upVector = upVector;
  45.       this.fieldWidth = fieldWidth;
  46.       this.fieldHeight = fieldHeight;
  47.     }
  48.   };
  49.   public class Commands
  50.   {
  51.     static MyView defaultView =
  52.       new MyView(
  53.         1930.1,1339.3,4399.3, 1930.1,1339.3,0.0,
  54.         0.0,1.0,0.0, 3279.8, 1702.6
  55.       );
  56.     static MyView topView =
  57.       new MyView(
  58.         1778.1,1108.2,635.7, 1778.1,1108.2,0.0,
  59.         0.0,1.0,0.0, 474.0, 246.0
  60.       );
  61.     static MyView bottomView =
  62.       new MyView(
  63.         1778.1,1108.2,-635.7, 1778.1,1108.2,0.0,
  64.         0.0,1.0,0.0, 474.0, 246.0
  65.       );
  66.     static MyView leftView =
  67.       new MyView(
  68.         -344.1,1108.2,66.1, 0.0,1108.2,66.1,
  69.         0.0,0.0,1.0, 256.5, 133.2
  70.       );
  71.     static MyView rightView =
  72.       new MyView(
  73.         344.1,1108.2,66.1, 0.0,1108.2,66.1,
  74.         0.0,0.0,1.0, 256.5, 133.2
  75.       );
  76.     static MyView SWIso =
  77.       new MyView(
  78.         265.1,-404.7,1579.0, 838.0,168.2,1006.2,
  79.         0.4,0.4,0.8, 739.7, 384.0
  80.       );
  81.     static MyView SEIso =
  82.       new MyView(
  83.         2105.6,780.7,393.7, 1532.7,1353.5,-179.2,
  84.         -0.4,0.4,0.8, 739.7, 384.0
  85.       );
  86.     static MyView NEIso =
  87.       new MyView(
  88.         1366.8,697.0,-345.2, 793.9,124.1,-918.0,
  89.         -0.4,-0.4,0.8, 739.7, 384.0
  90.       );
  91.     static MyView NWIso =
  92.       new MyView(
  93.         1003.9, 1882.3, 840.2, 1576.8, 1309.5,
  94.         267.3, 0.4, -0.4, 0.8, 739.7, 384.0
  95.       );
  96.     // Enacts a smooth transition from the current view
  97.     // to a new view
  98.     static Matrix3d SmoothViewTo(
  99.       MyView nv, double timeToTake
  100.     )
  101.     {
  102.       Matrix3d newViewMatrix = Matrix3d.Identity;
  103.       Document doc =
  104.         Application.DocumentManager.MdiActiveDocument;
  105.       Database db =
  106.         doc.Database;
  107.       Manager gsm =
  108.         doc.GraphicsManager;
  109.       // Get the current viewport
  110.       int vpn =
  111.         Convert.ToInt32(
  112.           Application.GetSystemVariable("CVPORT")
  113.         );
  114.       View view = gsm.GetGsView(vpn, true);
  115.       using (view)
  116.       {
  117.         // Set the frame rate to the standard eye FPS
  118.         view.BeginInteractivity(24);
  119.         Matrix3d viewMatrix = view.ViewingMatrix;
  120.         // Get the current view settings
  121.         MyView cv =
  122.           new MyView(
  123.             view.Position, view.Target, view.UpVector,
  124.             view.FieldWidth, view.FieldHeight
  125.           );
  126.         // Set up the start positions
  127.         Point3d intPos = cv.position;
  128.         Point3d intTgt = cv.target;
  129.         Vector3d intUpVec = cv.upVector;
  130.         double intWid = cv.fieldWidth;
  131.         double intHgt = cv.fieldHeight;
  132.         // Now animate the view change between the
  133.         // currentview and the viewToChangeTo
  134.         for (float mu = 0; mu  50 ? 0 : sleepTime));
  135.         }
  136.         view.EndInteractivity();
  137.         // Finally set the new view  
  138.         gsm.SetViewportFromView(vpn, view, true, true, false);
  139.         System.Windows.Forms.Application.DoEvents();
  140.       }
  141.       return newViewMatrix;
  142.     }
  143.     // Cosine interpolation
  144.     static double CosInterp(double y1, double y2, double mu)
  145.     {
  146.       double mu2;
  147.       mu2 = (1-Math.Cos(mu*Math.PI))/2;
  148.       return(y1*(1-mu2)+y2*mu2);
  149.     }
  150.     // Function to create a solid background of the same
  151.     // colour as the background of our 2D modelspace view
  152.     // (reduces the visual shock as the colour would
  153.     // otherwise switch to grey and back)
  154.     private static ObjectId CreateBackground()
  155.     {
  156.       const string bgKey = "TTIF_BG";
  157.       Document doc =
  158.         Application.DocumentManager.MdiActiveDocument;
  159.       Database db =
  160.         doc.Database;
  161.       ObjectId vtId = ObjectId.Null;
  162.       // Get the current viewport number
  163.       int vpn =
  164.         Convert.ToInt32(
  165.           Application.GetSystemVariable("CVPORT")
  166.         );
  167.       // No need to set the background if a corresponding
  168.       // 3D view already exists
  169.       View view =
  170.         doc.GraphicsManager.GetGsView(vpn, false);
  171.       if (view == null)
  172.       {
  173.         Transaction tr =
  174.           db.TransactionManager.StartTransaction();
  175.         using (tr)
  176.         {
  177.           ObjectId bgId = ObjectId.Null;
  178.           // Get or create our background dictionary
  179.           ObjectId bgdId =
  180.             Background.GetBackgroundDictionaryId(db, true);
  181.           DBDictionary bgd =
  182.             (DBDictionary)tr.GetObject(
  183.               bgdId,
  184.               OpenMode.ForRead
  185.             );
  186.           if (bgd.Contains(bgKey))
  187.           {
  188.             bgId = bgd.GetAt(bgKey);
  189.           }
  190.           else
  191.           {
  192.             // If our background doesn't exist...
  193.             // Get the 2D modelspace background colour
  194.             AcadPreferences prefs =
  195.               (AcadPreferences)Application.Preferences;
  196.             int rawCol =
  197.               (int)prefs.Display.GraphicsWinModelBackgrndColor;
  198.             // Create a background with the corresponding RGB
  199.             SolidBackground sb = new SolidBackground();
  200.             sb.Color =
  201.               new Autodesk.AutoCAD.Colors.EntityColor(
  202.                 (byte)(rawCol & 0x000000FF),
  203.                 (byte)((rawCol & 0x0000FF00) >> 8),
  204.                 (byte)((rawCol & 0x00FF0000) >> 16)
  205.               );
  206.             // Add it to the background dictionary
  207.             bgd.UpgradeOpen();
  208.             bgId = bgd.SetAt(bgKey, sb);
  209.             tr.AddNewlyCreatedDBObject(sb, true);
  210.           }
  211.           // Set the background on the active modelspace viewport
  212.           ViewportTable vt =
  213.             (ViewportTable)tr.GetObject(
  214.               db.ViewportTableId,
  215.               OpenMode.ForRead
  216.             );
  217.           foreach (ObjectId id in vt)
  218.           {
  219.             ViewportTableRecord vtr =
  220.               (ViewportTableRecord)tr.GetObject(
  221.                 id,
  222.                 OpenMode.ForRead
  223.               );
  224.             if (vtr.Name == "*Active")
  225.             {
  226.               vtId = id;
  227.               vtr.UpgradeOpen();
  228.               vtr.Background = bgId;
  229.             }
  230.           }
  231.           tr.Commit();
  232.         }
  233.       }
  234.       else
  235.         view.Dispose();
  236.       return vtId;
  237.     }
  238.     private static void RemoveBackground(ObjectId vtId)
  239.     {
  240.       Document doc =
  241.         Application.DocumentManager.MdiActiveDocument;
  242.       Database db =
  243.         doc.Database;
  244.       Transaction tr =
  245.         db.TransactionManager.StartTransaction();
  246.       using (tr)
  247.       {
  248.         // Open up the previously-modified viewport
  249.         ViewportTableRecord vtr =
  250.           (ViewportTableRecord)tr.GetObject(
  251.             vtId,
  252.             OpenMode.ForWrite
  253.           );
  254.         // And set its previous background
  255.         ObjectId obgId =
  256.           vtr.GetPreviousBackground(
  257.             DrawableType.SolidBackground
  258.           );
  259.         vtr.Background = obgId;
  260.         tr.Commit();
  261.       }
  262.     }
  263.     [CommandMethod("TV")]
  264.     static public void TransitionView()
  265.     {
  266.       Document doc =
  267.         Application.DocumentManager.MdiActiveDocument;
  268.       Database db =
  269.         doc.Database;
  270.       ObjectId vtId = CreateBackground();
  271.       SmoothViewTo(defaultView, 10);
  272.       SmoothViewTo(SWIso, 10);
  273.       SmoothViewTo(topView, 10);
  274.       SmoothViewTo(SEIso, 10);
  275.       SmoothViewTo(bottomView, 10);
  276.       SmoothViewTo(NEIso, 10);
  277.       SmoothViewTo(leftView, 10);
  278.       SmoothViewTo(NWIso, 10);
  279.       SmoothViewTo(rightView, 10);
  280.       SmoothViewTo(defaultView, 10);
  281.       if (vtId != ObjectId.Null)
  282.         RemoveBackground(vtId);
  283.     }
  284.   }
  285. }
A few comments on the code...
Fenton interpolates between views using his own "secret sauce", the CosInterp() function. This does some clever stuff to interpolate between the values provided. It's used to interpolate between the beginning and end states of the individual members of the co-ordinates of the various points and vectors - and the field width and height - that define a view.
I added some functionality to create a temporary background image attached to the active ViewportTableRecord with the same colour as the drawing canvas background (if in a standard 2D view). This allows the 3D view that gets created to have the same background colour, avoiding the shock of it flashing to grey and back. I admit that this code (in CreateBackground() and RemoveBackground()) doesn't feel especially elegant - I tried various different approaches such as modifying the view and the device attached to the view, but none of them worked in the way I wanted. So this is what I ended up with. I'd be very happy to hear from people who have found a better way to address this issue...
To see how the function works, draw some 3D geometry, load the application and run the TV command.
Here's a sample view prior to running the command:
And here's a snapshot I managed to take during the command, as the view was transitioning:

It's hard to do it justice with a static image, so the best is to give it a try.
I can see a few changes that people might want to make to the code:
the view definitions (to change their parameters or even to generate them dynamically).
the formula in the CosInterp() function.
the code towards the end of the SmoothViewTo() which pauses for a variable amount of time, depending on how close the view is from being transitioned.
When Fenton shared his original code within the DevTech team, Jeremy Tammik mentioned another interpolation algorithm based on  quaternion mathematics,  spherical linear interpolation (Slerp). In the next post in this series we'll take a look at a version implementing Slerp to do something very similar to the code in this post.
回复

举报

72

主题

2726

帖子

9

银币

社区元老

Rank: 75Rank: 75Rank: 75

铜币
3014
发表于 2009-5-16 11:33:00 | 显示全部楼层
March 02, 2009
Smoothly transitioning between 3D AutoCAD views using .NET - Part 2
Thanks again to Fenton Webb for providing the code behind the first post in the series and to Jeremy Tammik for providing the suggestion of this alternative implementation.
This post follows on from this previous post, which introduced a technique to smoothly transition between 3D views in AutoCAD. It applies a more standard algorithm - known as  spherical linear interpolation (or Slerp to its friends :-) - to interpolate between views, rather than interpolating individual values using Fenton's custom-built CosInterp() function. We still use CosInterp() to interpolate the width and height of the field of view, but otherwise the below code makes use of Slerp for the points and vectors it needs to adjust.
Here's the modified C# code, which can be added to the same project as that containing the code from the previous post (to compare the execution):
  1. using System;
  2. using System.Threading;
  3. using System.Drawing;
  4. using Autodesk.AutoCAD.ApplicationServices;
  5. using Autodesk.AutoCAD.EditorInput;
  6. using Autodesk.AutoCAD.DatabaseServices;
  7. using Autodesk.AutoCAD.Runtime;
  8. using Autodesk.AutoCAD.Geometry;
  9. using Autodesk.AutoCAD.GraphicsInterface;
  10. using Autodesk.AutoCAD.GraphicsSystem;
  11. using Autodesk.AutoCAD.Interop;
  12. namespace ViewTransitionsSlerp
  13. {
  14.   public class MyView
  15.   {
  16.     public Point3d position;
  17.     public Point3d target;
  18.     public Vector3d upVector;
  19.     public double fieldWidth;
  20.     public double fieldHeight;
  21.     // Default constructor
  22.     public MyView(){}
  23.     // For constant defines below SWIso etc
  24.     public MyView(
  25.       double x1, double y1, double z1,
  26.       double x2, double y2, double z2,
  27.       double x3, double y3, double z3,
  28.       double x4, double y4
  29.     )
  30.     {
  31.       position = new Point3d(x1, y1, z1);
  32.       target = new Point3d(x2, y2, z2);
  33.       upVector = new Vector3d(x3, y3, z3);
  34.       fieldWidth = x4;
  35.       fieldHeight= y4;
  36.     }
  37.     public MyView(
  38.       Point3d position, Point3d target, Vector3d upVector,
  39.       double fieldWidth, double fieldHeight
  40.     )
  41.     {
  42.       this.position = position;
  43.       this.target = target;
  44.       this.upVector = upVector;
  45.       this.fieldWidth = fieldWidth;
  46.       this.fieldHeight = fieldHeight;
  47.     }
  48.   };
  49.   public class Commands
  50.   {
  51.     static MyView defaultView =
  52.       new MyView(
  53.         1930.1,1339.3,4399.3, 1930.1,1339.3,0.0,
  54.         0.0,1.0,0.0, 3279.8, 1702.6
  55.       );
  56.     static MyView topView =
  57.       new MyView(
  58.         1778.1,1108.2,635.7, 1778.1,1108.2,0.0,
  59.         0.0,1.0,0.0, 474.0, 246.0
  60.       );
  61.     static MyView bottomView =
  62.       new MyView(
  63.         1778.1,1108.2,-635.7, 1778.1,1108.2,0.0,
  64.         0.0,1.0,0.0, 474.0, 246.0
  65.       );
  66.     static MyView leftView =
  67.       new MyView(
  68.         -344.1,1108.2,66.1, 0.0,1108.2,66.1,
  69.         0.0,0.0,1.0, 256.5, 133.2
  70.       );
  71.     static MyView rightView =
  72.       new MyView(
  73.         344.1,1108.2,66.1, 0.0,1108.2,66.1,
  74.         0.0,0.0,1.0, 256.5, 133.2
  75.       );
  76.     static MyView SWIso =
  77.       new MyView(
  78.         265.1,-404.7,1579.0, 838.0,168.2,1006.2,
  79.         0.4,0.4,0.8, 739.7, 384.0
  80.       );
  81.     static MyView SEIso =
  82.       new MyView(
  83.         2105.6,780.7,393.7, 1532.7,1353.5,-179.2,
  84.         -0.4,0.4,0.8, 739.7, 384.0
  85.       );
  86.     static MyView NEIso =
  87.       new MyView(
  88.         1366.8,697.0,-345.2, 793.9,124.1,-918.0,
  89.         -0.4,-0.4,0.8, 739.7, 384.0
  90.       );
  91.     static MyView NWIso =
  92.       new MyView(
  93.         1003.9, 1882.3, 840.2, 1576.8, 1309.5,
  94.         267.3, 0.4, -0.4, 0.8, 739.7, 384.0
  95.       );
  96.     // Enacts a smooth transition from the current view to a
  97.     // new view using spherical linear interpolation (Slerp)
  98.     static Matrix3d SmoothViewToSlerp(
  99.       MyView nv, double timeToTake
  100.     )
  101.     {
  102.       Matrix3d newViewMatrix = Matrix3d.Identity;
  103.       Document doc =
  104.         Application.DocumentManager.MdiActiveDocument;
  105.       Database db =
  106.         doc.Database;
  107.       Manager gsm =
  108.         doc.GraphicsManager;
  109.       // Get the current viewport
  110.       int vpn =
  111.         Convert.ToInt32(
  112.           Application.GetSystemVariable("CVPORT")
  113.         );
  114.       View view = gsm.GetGsView(vpn, true);
  115.       using (view)
  116.       {
  117.         // Set the frame rate to the standard eye FPS
  118.         view.BeginInteractivity(24);
  119.         Matrix3d viewMatrix = view.ViewingMatrix;
  120.         // Get the current view settings
  121.         MyView cv =
  122.           new MyView(
  123.             view.Position, view.Target, view.UpVector,
  124.             view.FieldWidth, view.FieldHeight
  125.           );
  126.         // Set up the start positions
  127.         Point3d intPos = cv.position;
  128.         Point3d intTgt = cv.target;
  129.         Vector3d intUpVec = cv.upVector;
  130.         double intWid = cv.fieldWidth;
  131.         double intHgt = cv.fieldHeight;
  132.         // Now animate the view change between the
  133.         // currentview and the viewToChangeTo
  134.         for (float mu = 0; mu  50 ? 0 : sleepTime));
  135.         }
  136.         view.EndInteractivity();
  137.         // Finally set the new view  
  138.         gsm.SetViewportFromView(vpn, view, true, true, false);
  139.         System.Windows.Forms.Application.DoEvents();
  140.       }
  141.       return newViewMatrix;
  142.     }
  143.     // Cosine interpolation
  144.     static double CosInterp(double y1, double y2, double mu)
  145.     {
  146.       double mu2;
  147.       mu2 = (1-Math.Cos(mu*Math.PI))/2;
  148.       return(y1*(1-mu2)+y2*mu2);
  149.     }
  150.     // Spherical linear interpolation
  151.     static Vector3d Slerp(Vector3d from, Vector3d to, float step)
  152.     {
  153.       if (step == 0)
  154.         return from;
  155.       if (from == to || step == 1)
  156.         return to;
  157.       // Normalize the vectors
  158.       Vector3d unitfrom = from.GetNormal(),
  159.               unitto = to.GetNormal();
  160.       // Calculate the included angle
  161.       double theta =
  162.         Math.Acos(unitfrom.DotProduct(unitto));
  163.       if (theta == 0)
  164.         return to;
  165.       // Avoid the repeated sine calculation
  166.       double st =
  167.         Math.Sin(theta);
  168.       // Return the geometric spherical linear interpolation
  169.       return
  170.         from * (Math.Sin((1 - step) * theta) / st) +
  171.         to * Math.Sin(step * theta) / st;
  172.     }
  173.     // Function to create a solid background of the same
  174.     // colour as the background of our 2D modelspace view
  175.     // (reduces the visual shock as the colour would
  176.     // otherwise switch to grey and back)
  177.     private static ObjectId CreateBackground()
  178.     {
  179.       const string bgKey = "TTIF_BG";
  180.       Document doc =
  181.         Application.DocumentManager.MdiActiveDocument;
  182.       Database db =
  183.         doc.Database;
  184.       ObjectId vtId = ObjectId.Null;
  185.       // Get the current viewport number
  186.       int vpn =
  187.         Convert.ToInt32(
  188.           Application.GetSystemVariable("CVPORT")
  189.         );
  190.       // No need to set the background if a corresponding
  191.       // 3D view already exists
  192.       View view =
  193.         doc.GraphicsManager.GetGsView(vpn, false);
  194.       if (view == null)
  195.       {
  196.         Transaction tr =
  197.           db.TransactionManager.StartTransaction();
  198.         using (tr)
  199.         {
  200.           ObjectId bgId = ObjectId.Null;
  201.           // Get or create our background dictionary
  202.           ObjectId bgdId =
  203.             Background.GetBackgroundDictionaryId(db, true);
  204.           DBDictionary bgd =
  205.             (DBDictionary)tr.GetObject(
  206.               bgdId,
  207.               OpenMode.ForRead
  208.             );
  209.           if (bgd.Contains(bgKey))
  210.           {
  211.             bgId = bgd.GetAt(bgKey);
  212.           }
  213.           else
  214.           {
  215.             // If our background doesn't exist...
  216.             // Get the 2D modelspace background colour
  217.             AcadPreferences prefs =
  218.               (AcadPreferences)Application.Preferences;
  219.             int rawCol =
  220.               (int)prefs.Display.GraphicsWinModelBackgrndColor;
  221.             // Create a background with the corresponding RGB
  222.             SolidBackground sb = new SolidBackground();
  223.             sb.Color =
  224.               new Autodesk.AutoCAD.Colors.EntityColor(
  225.                 (byte)(rawCol & 0x000000FF),
  226.                 (byte)((rawCol & 0x0000FF00) >> 8),
  227.                 (byte)((rawCol & 0x00FF0000) >> 16)
  228.               );
  229.             // Add it to the background dictionary
  230.             bgd.UpgradeOpen();
  231.             bgId = bgd.SetAt(bgKey, sb);
  232.             tr.AddNewlyCreatedDBObject(sb, true);
  233.           }
  234.           // Set the background on the active modelspace viewport
  235.           ViewportTable vt =
  236.             (ViewportTable)tr.GetObject(
  237.               db.ViewportTableId,
  238.               OpenMode.ForRead
  239.             );
  240.           foreach (ObjectId id in vt)
  241.           {
  242.             ViewportTableRecord vtr =
  243.               (ViewportTableRecord)tr.GetObject(
  244.                 id,
  245.                 OpenMode.ForRead
  246.               );
  247.             if (vtr.Name == "*Active")
  248.             {
  249.               vtId = id;
  250.               vtr.UpgradeOpen();
  251.               vtr.Background = bgId;
  252.             }
  253.           }
  254.           tr.Commit();
  255.         }
  256.       }
  257.       else
  258.         view.Dispose();
  259.       return vtId;
  260.     }
  261.     private static void RemoveBackground(ObjectId vtId)
  262.     {
  263.       Document doc =
  264.         Application.DocumentManager.MdiActiveDocument;
  265.       Database db =
  266.         doc.Database;
  267.       Transaction tr =
  268.         db.TransactionManager.StartTransaction();
  269.       using (tr)
  270.       {
  271.         // Open up the previously-modified viewport
  272.         ViewportTableRecord vtr =
  273.           (ViewportTableRecord)tr.GetObject(
  274.             vtId,
  275.             OpenMode.ForWrite
  276.           );
  277.         // And set its previous background
  278.         ObjectId obgId =
  279.           vtr.GetPreviousBackground(
  280.             DrawableType.SolidBackground
  281.           );
  282.         vtr.Background = obgId;
  283.         tr.Commit();
  284.       }
  285.     }
  286.     [CommandMethod("TVS")]
  287.     static public void TransitionViewSlerp()
  288.     {
  289.       Document doc =
  290.         Application.DocumentManager.MdiActiveDocument;
  291.       Database db =
  292.         doc.Database;
  293.       ObjectId vtId = CreateBackground();
  294.       SmoothViewToSlerp(defaultView, 10);
  295.       SmoothViewToSlerp(SWIso, 10);
  296.       SmoothViewToSlerp(topView, 10);
  297.       SmoothViewToSlerp(SEIso, 10);
  298.       SmoothViewToSlerp(bottomView, 10);
  299.       SmoothViewToSlerp(NEIso, 10);
  300.       SmoothViewToSlerp(leftView, 10);
  301.       SmoothViewToSlerp(NWIso, 10);
  302.       SmoothViewToSlerp(rightView, 10);
  303.       SmoothViewToSlerp(defaultView, 10);
  304.       if (vtId != ObjectId.Null)
  305.         RemoveBackground(vtId);
  306.     }
  307.   }
  308. }
What's especially notable about this implementation is actually how similarly it works to the previous one. Fenton came up with a pretty nice interpolation technique without knowing about Slerp which produces very similar - possibly identical, although I haven't verified them - results. Very cool.
From my side I hadn't heard of Slerp and only had the vaguest idea of what a  quaternion was - even now I wouldn't know a quaternion if it bit me on the nose, so it's a good thing the wikipedia article contains a geometric alternative to the quaternion Slerp formula.
So why use one technique over the other? There are a couple of possible differentiators that may make a difference to people.
The first is the possibility - and this is not something I've verified through performance benchmarking - that the Slerp implementation is more efficient. We need fewer calls to Slerp() than we used for CosInterp(), simply because we're interpolating multiple values at the same time. But this isn't likely to be a noticeable difference in any real-world application, so isn't something that would concern me, either way.
The second differentiator is a potential deployment issue: a bug was introduced with Service Pack 1 of the .NET Framework 3.5 that can cause problems with vector arithmetic in AutoCAD .NET applications. Jimmy Bergmark reported on this, back in August, and a hotfix was posted by Microsoft in early December. I hit this issue after having installed a pre-release version of AutoCAD 2010 (which installed the .NET Framework 3.5 SP1) but I hit the problem when executing code in AutoCAD 2009. Installing the hotfix solved the problem, but in this case the more fundamental implementation not relying on Vector3d objects proved to be more reliable.
In reality, though, avoiding vector arithmetic isn't really an option for most developers, so this is being addressed on a few fronts: AutoCAD 2009 Update 2 apparently works around it (not sure how I missed that update, but there you go) as does AutoCAD 2010... and it also seems that any day now Microsoft will be pushing out a fixed version of the .NET Framework 3.5 SP1 in a general distribution release via Windows Update (which means that any Windows user running .NET Framework 2.0 or higher will get it). So I'm a little less worried about the impact of this issue than I was when I first saw it manifest itself. For ADN members who would like additional, detailed information on this issue, please visit this DevNote on the ADN site (login required).
All this to say that the two versions of the code are much the same, when all is said and done. I've provided both mainly for the purposes of intellectual curiosity and in case the techniques shown are relevant for other scenarios.
回复

举报

3

主题

13

帖子

1

银币

初来乍到

Rank: 1

铜币
25
发表于 2009-5-21 10:43:00 | 显示全部楼层
看样子,我要补习英语了
回复

举报

32

主题

651

帖子

8

银币

中流砥柱

Rank: 25

铜币
779
发表于 2009-5-21 13:57:00 | 显示全部楼层
学习了!谢谢!
回复

举报

发表回复

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

本版积分规则

  • 微信公众平台

  • 扫描访问手机版

  • 点击图片下载手机App

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

GMT+8, 2025-3-13 10:42 , Processed in 1.892750 second(s), 77 queries .

© 2020-2025 乐筑天下

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