ArcGIS Engine 三维开发
来自:http://www.iarcgis.com/?p=826
在三维中,经常使用的一个功能就是播放动画,也就是我们要对一条动画轨迹进行播放,而在ArcGIS Engine中做3D开发的时候,轨迹有两个对应的对象
IAnimationTrack和IAGAnimationTrack,
如果在帮助中仔细查看还会发现更多跟这两个类似的区别,一个接口比另一个接口多两个字母AG,
如IAnimationTracks和IAGAnimationTracks,IKeyframe和IAGKeyframe。
我们看下这些的描述
IAGKeyframe:访问运动对象的关键帧(Provides access to keyframes of animated objects. )
IKeyframe:访问运动对象的关键帧(Provides access to keyframes of animated objects.)
从描述上看,没有任何区别,那么为什么会有两个这样的接口,带AG的出来的比较晚,而且位于ESRI.ArcGIS.Animation中,而不带AG的是早期的接口位于ESRI.ArcGIS.Analyst3D中,而且这些接口的属性和方法都很类似:
Ikeyframe
IAGKeyframe
1.1 原因何在
既然两个接口提供的方法和接口很类似,为什么会有两套这样的接口呢?原来带AG的是后来出现的,而且是在9.2的时候增加的,在9.2的时候增加了Animation等类库,看下面的描述:
Animation and AnimationUI—Contain objects to work with animations in ArcMap, ArcScene, or ArcGlobe. An animation in ArcMap, ArcScene, or ArcGlobe is composed of animation tracks (AGAnimationTracks), which are further composed of keyframes (AGAnimationKeyframes) of the same type. Each keyframe stores properties of the animation objects. When an animation is played, keyframes are interpolated, and the interpolated properties are then applied to the animated objects to create the dynamic visual effect.
在帮助中,我们可以看到更多的信息,首先看到实现IAGAnimationTrack的接口有两个类即AGAnimationTrack和AnimationTrack,也就是说凡是带了AG的接口很多都被早期的对象继承,如下:
AGAnimationTrack类只实现了IAGAnimationTrack接口,如下图:
而AnimationTrack类不仅仅实现了1AnimationTrack接口,还实现了 1AGAnimationTrack接口,如下图:
1.1 后出现的不一定就节省力气
1.1.1 关键帧创建
在创建关键帧的时候两者差别不大,除了创建的时候的参数不一样,其他几乎没有变化,下面为使用IKeyframe创建的:
IKeyframe pKeyframe = new GlobeCameraKeyframeClass(); pKeyframe.Name = "Key" + Convert.ToString(_AnimationTrack.KeyframeCount + 1); IScene pScene = globe.Globe as IScene; pKeyframe.CaptureProperties(pScene, globe.GlobeDisplay.ActiveViewer.Camera); _AnimationTrack.InsertKeyframe(pKeyframe, -1); for (int index = 0; index < _AnimationTrack.KeyframeCount; index++) { _AnimationTrack.get_Keyframe(index).TimeStamp = (double)index / (double)(_AnimationTrack.KeyframeCount - 1); }
下面为使用IAGKeyframe创建的:
public static void InsertKeyfr(IGlobe pGlobe, string pTrackName) { IAGAnimationTracks pTracks = pGlobe as IAGAnimationTracks; IAGAnimationTrack _AnimationTrack = GetAGAnimationTrack(pTracks, pTrackName); if (_AnimationTrack == null) { _AnimationTrack = new AGAnimationTrackClass(); _AnimationTrack.Name = pTrackName; pTracks.AddTrack(_AnimationTrack); } IAGAnimationTrackKeyframes pAGKyeFrames = _AnimationTrack as IAGAnimationTrackKeyframes; IAGKeyframe pKeyframe = new GlobeCameraKeyframeClass(); pKeyframe.Name = "Capture" + Convert.ToString(pAGKyeFrames.KeyframeCount + 1); IScene pScene = pGlobe.GlobeDisplay.Scene; //还可以直接转换 pKeyframe.CaptureProperties(pGlobe as IAGAnimationContainer, pGlobe.GlobeDisplay.ActiveViewer.Camera); (_AnimationTrack as IAGAnimationTrackKeyframes).InsertKeyframe(pKeyframe, -1); for (int index = 0; index < pAGKyeFrames.KeyframeCount; index++) { pAGKyeFrames.get_Keyframe(index).TimeStamp = (double)index / (double)(pAGKyeFrames.KeyframeCount - 1); } //更新窗体; }
1.1.1 关键帧获取
但是有的时候不带AG的比带了AG的方便,比如要获取一条轨迹的关键帧,使用IAnimationTrack接口的时候只需要下面两个步骤:
- IAnimationTrack.KeyframeCount
- IAnimationTrack.Keyframe
而IAGAnimationTrack接口则需要3个步骤:
- IAGAnimationTrackKeyframes
- IAGAnimationTrackKeyframes.KeyframeCount
- IAGAnimationTrackKeyframes.Keyframe
1.1.2 播放动画
而在播放动画的饿时候使用IAnimationTracks,我们只需要用下面的步骤代码:
在播放的时候用下面的代码是可以实现动画播放的:
IAnimationTracks pTracks = globe.Globe as IAnimationTracks; for (int i = 0; i < pTracks.TrackCount; i++) { IAnimationTrack pTrack = pTracks.Tracks.get_Element(i) as IAnimationTrack; pTrack.IsEnabled = true;//设置为true 才可以播放这条轨迹 } DateTime startTime = DateTime.Now; TimeSpan timeSpan; double elapsedTime; double duration = 10; bool play = true; do { timeSpan = (DateTime.Now).Subtract(startTime); elapsedTime = timeSpan.TotalSeconds; if (elapsedTime > duration) { play = false; elapsedTime = duration; } pTracks.ApplyTracks(globe.GlobeDisplay.ActiveViewer, elapsedTime, duration); globe.GlobeDisplay.RefreshViewers(); } while (play);
我们在前面说到了,带AG的接口提供的方法和属性和不带的非常类似,但下面的代码播放之后是不能实现动画播放的
for (int i = 0; i < pTracks.TrackCount; i++) { IAGAnimationTrack pAnimationTrack = pTracks.AGTracks.get_Element(i) as IAGAnimationTrack; pAnimationTrack.IsEnabled = true; } DateTime startTime = DateTime.Now; TimeSpan timeSpan; double elapsedTime; double duration = 10; bool play = true; do { timeSpan = (DateTime.Now).Subtract(startTime); elapsedTime = timeSpan.TotalSeconds; if (elapsedTime > duration) { play = false; elapsedTime = duration; } pTracks.ApplyTracks(false, duration); this.globe.GlobeDisplay.RefreshViewers(); } while (play);
如何才能播放呢,既然已经知道带AG的来自Animation库,那就应该在这个库中找,使用下面的接口:
如果对ArcGlobe的动画非常熟悉的朋友,应该知道这4个方法对应了播放工具上的四个操作,录制,破防。暂停和停止
private IAGAnimationEnvironment CreatAnimationEnvironment(IGlobe pGlobe) { DateTime startTime = DateTime.Now; Double playTimeInterval = 10; IBasicScene2 pBasicScene2 = pGlobe as IBasicScene2; _pAGAnimationEnvironment = pBasicScene2.AnimationExtension.AnimationEnvironment; _pAGAnimationEnvironment.IsIntervalPlay = true; _pAGAnimationEnvironment.PlayInAllViewers = true; _pAGAnimationEnvironment.PlayMode = esriAnimationPlayMode.esriAnimationPlayOnceForward; _pAGAnimationEnvironment.AnimationDuration = playTimeInterval; _pAGAnimationEnvironment.PlayType = esriAnimationPlayType.esriAnimationPlayTypeDuration; _pAGAnimationEnvironment.PlayTime = playTimeInterval; _pAGAnimationEnvironment.PutPlayInterval(0, playTimeInterval);//尤其关键,设置播放时间段。 _pAGAnimationEnvironment.RestoreState = true; IArray pArr = new ArrayClass(); return _pAGAnimationEnvironment; } //List存放了我路径轨迹的名称 private void PlayAnimaiton(IGlobe pGlobe) { IAGAnimationTracks pAGAnimationTracks = pGlobe as IAGAnimationTracks; IAGAnimationUtils pAGAnimationUtils = new AGAnimationUtilsClass(); IAGAnimationPlayer pAGAnimaitonPlayer = pAGAnimationUtils as IAGAnimationPlayer; _pAGAnimationEnvironment = CreatAnimationEnvironment(pGlobe); List pList = new List(); if (checkedListBoxtracks.SelectedItems.Count > 0) { for (int j = 0; j < checkedListBoxtracks.CheckedItems.Count; j++) { pList.Add(checkedListBoxtracks.CheckedItems[j].ToString()); } } for (int i = 0; i < pAGAnimationTracks.TrackCount; i++) { IAGAnimationTrack pT=pAGAnimationTracks.AGTracks.get_Element(i) as IAGAnimationTrack; if (pList.Contains(pT.Name)) { pT.IsEnabled = true; } else { pT.IsEnabled = false; } } pAGAnimaitonPlayer.PlayAnimation(pAGAnimationTracks, _pAGAnimationEnvironment, null); //pAGAnimationUtils.SaveAnimationFile(pAGAnimationTracks.AnimationObjectContainer, "C:\\test.asa", ESRI.ArcGIS.esriSystem.esriArcGISVersion.esriArcGISVersion93); }
1.3 但后出现的比较灵活
在使用不带AG的播放动画是,播放结束后,是不能回到原来的状态,但是后者却可以,还有就是在播放的时候,前者是不能停止和暂停(除非播放结束或系统出现问题),但是后者却可以,还有就是后者提供了录制的功能,而前者没有。同时,后者在播放的时候,只要将播放环境接口IAGAnimationEnvironment中的信息设置OK后,就不用自己去写while循环用来判断时间。在创建关键帧的时候,我们往往都是创建路径,然后将帧插入到路径中,但是后者有有个默认的路径,下面的代码就是向默认的路径中捕获当前的视图,也就是ArcGlobe中的那个照相机的功能:
ESRI.ArcGIS.Animation.IAGAnimationUtils pAnimationUtils = new ESRI.ArcGIS.Animation.AGAnimationUtilsClass(); ESRI.ArcGIS.Animation.IAGAnimationTracks pAnimationTracks = (ESRI.ArcGIS.Animation.IAGAnimationTracks)globe; ESRI.ArcGIS.Analyst3D.IBasicScene2 pBasicScene2 = (ESRI.ArcGIS.Analyst3D.IBasicScene2)globe; ESRI.ArcGIS.Animation.IAGAnimationEnvironment pAnimationEnvironment = pBasicScene2.AnimationExtension.AnimationEnvironment; pAnimationUtils.CaptureCurrentView(pAnimationTracks, pAnimationEnvironment);
作者
刘宇