Sei sulla pagina 1di 9

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka .

1 z 9 e:

Through the Interface


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):
using using using using using using using using using using using System; System.Threading; System.Drawing; Autodesk.AutoCAD.ApplicationServices; Autodesk.AutoCAD.EditorInput; Autodesk.AutoCAD.DatabaseServices; Autodesk.AutoCAD.Runtime; Autodesk.AutoCAD.Geometry; Autodesk.AutoCAD.GraphicsInterface; Autodesk.AutoCAD.GraphicsSystem; Autodesk.AutoCAD.Interop;

namespace ViewTransitionsSlerp { public class MyView { public Point3d position; public Point3d target; public Vector3d upVector; public double fieldWidth; public double fieldHeight; // Default constructor public MyView(){} // For constant defines below SWIso etc public MyView( double x1, double y1, double z1, double x2, double y2, double z2, double x3, double y3, double z3, double x4, double y4 ) { position = new Point3d(x1, y1, z1); target = new Point3d(x2, y2, z2); upVector = new Vector3d(x3, y3, z3); fieldWidth = x4; fieldHeight= y4; } public MyView( Point3d position, Point3d target, Vector3d upVector, double fieldWidth, double fieldHeight

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 2 z 9 e:

) { this.position = position; this.target = target; this.upVector = upVector; this.fieldWidth = fieldWidth; this.fieldHeight = fieldHeight; } }; public class Commands { static MyView defaultView = new MyView( 1930.1,1339.3,4399.3, 1930.1,1339.3,0.0, 0.0,1.0,0.0, 3279.8, 1702.6 ); static MyView topView = new MyView( 1778.1,1108.2,635.7, 1778.1,1108.2,0.0, 0.0,1.0,0.0, 474.0, 246.0 ); static MyView bottomView = new MyView( 1778.1,1108.2,-635.7, 1778.1,1108.2,0.0, 0.0,1.0,0.0, 474.0, 246.0 ); static MyView leftView = new MyView( -344.1,1108.2,66.1, 0.0,1108.2,66.1, 0.0,0.0,1.0, 256.5, 133.2 ); static MyView rightView = new MyView( 344.1,1108.2,66.1, 0.0,1108.2,66.1, 0.0,0.0,1.0, 256.5, 133.2 ); static MyView SWIso = new MyView( 265.1,-404.7,1579.0, 838.0,168.2,1006.2, 0.4,0.4,0.8, 739.7, 384.0 ); static MyView SEIso = new MyView( 2105.6,780.7,393.7, 1532.7,1353.5,-179.2, -0.4,0.4,0.8, 739.7, 384.0 ); static MyView NEIso = new MyView( 1366.8,697.0,-345.2, 793.9,124.1,-918.0, -0.4,-0.4,0.8, 739.7, 384.0 ); static MyView NWIso = new MyView( 1003.9, 1882.3, 840.2, 1576.8, 1309.5, 267.3, 0.4, -0.4, 0.8, 739.7, 384.0 ); // Enacts a smooth transition from the current view to a // new view using spherical linear interpolation (Slerp) static Matrix3d SmoothViewToSlerp( MyView nv, double timeToTake ) { Matrix3d newViewMatrix = Matrix3d.Identity;

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 3 z 9 e:

Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Manager gsm = doc.GraphicsManager; // Get the current viewport int vpn = Convert.ToInt32( Application.GetSystemVariable("CVPORT") ); View view = gsm.GetGsView(vpn, true); using (view) { // Set the frame rate to the standard eye FPS view.BeginInteractivity(24); Matrix3d viewMatrix = view.ViewingMatrix; // Get the current view settings MyView cv = new MyView( view.Position, view.Target, view.UpVector, view.FieldWidth, view.FieldHeight ); // Set up the start positions Point3d intPos = cv.position; Point3d intTgt = cv.target; Vector3d intUpVec = cv.upVector; double intWid = cv.fieldWidth; double intHgt = cv.fieldHeight; // Now animate the view change between the // currentview and the viewToChangeTo for (float mu = 0; mu <= 1; mu += 0.01F) { // First convert the positions to vectors // (so we can simply call the existing function) Vector3d startPos = cv.position - Point3d.Origin, endPos = nv.position - Point3d.Origin, // Then get the target vectors relative // to the view position from = cv.target - cv.position, to = nv.target - nv.position, // Now Slerp the various vectors res1 = Slerp(startPos, endPos, mu), res2 = Slerp(from, to, mu), res3 = Slerp(cv.upVector, nv.upVector, mu); // And then we extract the relevant information...

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 4 z 9 e:

// Get a point from the position vector intPos = Point3d.Origin + res1; // Get the target point relative to that position intTgt = intPos + res2; // And the up-vector is easy :-) intUpVec = res3; // Let's use our previous interpolate function // for the field width and height // Interpolate Width intWid = CosInterp(cv.fieldWidth, nv.fieldWidth, mu); // Interpolate Height intHgt = CosInterp(cv.fieldHeight, nv.fieldHeight, mu); // Now set the interpolated view view.SetView(intPos, intTgt, intUpVec, intWid, intHgt); // Update the control view.Update(); // Decrease the sleep time, or rather increase the // speed of the view change as we work double sleepTime = timeToTake - (mu * 10); Thread.Sleep((int)(sleepTime > 50 ? 0 : sleepTime)); } view.EndInteractivity(); // Finally set the new view gsm.SetViewportFromView(vpn, view, true, true, false); System.Windows.Forms.Application.DoEvents(); } return newViewMatrix; } // Cosine interpolation static double CosInterp(double y1, double y2, double mu) { double mu2; mu2 = (1-Math.Cos(mu*Math.PI))/2; return(y1*(1-mu2)+y2*mu2); } // Spherical linear interpolation

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 5 z 9 e:

static Vector3d Slerp(Vector3d from, Vector3d to, float step) { if (step == 0) return from; if (from == to || step == 1) return to; // Normalize the vectors Vector3d unitfrom = from.GetNormal(), unitto = to.GetNormal(); // Calculate the included angle double theta = Math.Acos(unitfrom.DotProduct(unitto)); if (theta == 0) return to; // Avoid the repeated sine calculation double st = Math.Sin(theta); // Return the geometric spherical linear interpolation return from * (Math.Sin((1 - step) * theta) / st) + to * Math.Sin(step * theta) / st; } // // // // Function to create a solid background of the same colour as the background of our 2D modelspace view (reduces the visual shock as the colour would otherwise switch to grey and back)

private static ObjectId CreateBackground() { const string bgKey = "TTIF_BG"; Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; ObjectId vtId = ObjectId.Null; // Get the current viewport number int vpn = Convert.ToInt32( Application.GetSystemVariable("CVPORT") ); // No need to set the background if a corresponding // 3D view already exists View view = doc.GraphicsManager.GetGsView(vpn, false); if (view == null) {

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 6 z 9 e:

Transaction tr = db.TransactionManager.StartTransaction(); using (tr) { ObjectId bgId = ObjectId.Null; // Get or create our background dictionary ObjectId bgdId = Background.GetBackgroundDictionaryId(db, true); DBDictionary bgd = (DBDictionary)tr.GetObject( bgdId, OpenMode.ForRead ); if (bgd.Contains(bgKey)) { bgId = bgd.GetAt(bgKey); } else { // If our background doesn't exist... // Get the 2D modelspace background colour AcadPreferences prefs = (AcadPreferences)Application.Preferences; int rawCol = (int)prefs.Display.GraphicsWinModelBackgrndColor; // Create a background with the corresponding RGB SolidBackground sb = new SolidBackground(); sb.Color = new Autodesk.AutoCAD.Colors.EntityColor( (byte)(rawCol & 0x000000FF), (byte)((rawCol & 0x0000FF00) >> 8), (byte)((rawCol & 0x00FF0000) >> 16) ); // Add it to the background dictionary bgd.UpgradeOpen(); bgId = bgd.SetAt(bgKey, sb); tr.AddNewlyCreatedDBObject(sb, true); } // Set the background on the active modelspace viewport ViewportTable vt = (ViewportTable)tr.GetObject( db.ViewportTableId, OpenMode.ForRead ); foreach (ObjectId id in vt) { ViewportTableRecord vtr = (ViewportTableRecord)tr.GetObject( id, OpenMode.ForRead ); if (vtr.Name == "*Active") {

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 7 z 9 e:

vtId = id; vtr.UpgradeOpen(); vtr.Background = bgId; } } tr.Commit(); } } else view.Dispose(); return vtId; } private static void RemoveBackground(ObjectId vtId) { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; Transaction tr = db.TransactionManager.StartTransaction(); using (tr) { // Open up the previously-modified viewport ViewportTableRecord vtr = (ViewportTableRecord)tr.GetObject( vtId, OpenMode.ForWrite ); // And set its previous background ObjectId obgId = vtr.GetPreviousBackground( DrawableType.SolidBackground ); vtr.Background = obgId; tr.Commit(); } } [CommandMethod("TVS")] static public void TransitionViewSlerp() { Document doc = Application.DocumentManager.MdiActiveDocument; Database db = doc.Database; ObjectId vtId = CreateBackground(); SmoothViewToSlerp(defaultView, 10); SmoothViewToSlerp(SWIso, 10); SmoothViewToSlerp(topView, 10); SmoothViewToSlerp(SEIso, 10); SmoothViewToSlerp(bottomView, 10); SmoothViewToSlerp(NEIso, 10); SmoothViewToSlerp(leftView, 10); SmoothViewToSlerp(NWIso, 10); SmoothViewToSlerp(rightView, 10); SmoothViewToSlerp(defaultView, 10);

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 8 z 9 e:

if (vtId != ObjectId.Null) RemoveBackground(vtId); } } }

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. Posted at 11:27 AM in AutoCAD, AutoCAD .NET, Graphics system | Permalink TrackBack
TrackBack URL for this entry: http://www.typepad.com/services/trackback/6a00d83452464869e20112790f190728a4 Listed below are links to weblogs that reference Smoothly transitioning between 3D AutoCAD views using .NET - Part 2:

Comments

Tony Tanzillo said...

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Through the Interfac Smoothly transitioning between 3D AutoCAD views using... Strnka . 9 z 9 e:

Thanks for another fine example. It should be worth noting that it was Albert Szilvasy that originally identified, repro'd, and developed the workaround that was reported to and published by Microsoft. See http://support.microsoft.com/kb/957542 The code appearing in the Workaround section in that document should look familiar :) ReplyMarch 02, 2009 at 06:54 PM

Kean Walmsley said... Great - thanks, Tony. Yes, indeed - very familiar. :-) Kean ReplyMarch 02, 2009 at 07:49 PM Comment below or sign in with TypePad Facebook Twitter and more...

(You can use HTML tags like <b> <i> and <ul> to style your text. URLs automatically linked.)

Email address is not displayed with comment.

Name Email Address Web Site URL Post Preview

http://through-the-interfac e.typepad.c om/through_the_interfac e/2009/03/smoothly-tra...

29.11.2012

Potrebbero piacerti anche