STK + C# + セシウム共同プログラミング (2): CZML ファイルの生成とロード

概要

この記事は、前回のブログ投稿の続きです. 前回の記事では、C# .NET Framework (Web Service) + STK + Cesium フロントエンド ディスプレイの関連技術を検証しました. この記事では、Pro チュートリアルを通じて STK を作成する方法を示します.インスタンスおよび STK インストールに付属する Export CZML プラグイン. シーンの作成、オブジェクトの作成、Access の計算、プラグインによる CZML ファイルの出力、およびクライアント側でのシーンの読み込みと表示。

CZML は、一時的な動的グラフィックス シーンを JSON 形式で記述するための仕様です。主に Cesium クライアント ブラウザでの表示に使用される CZML は、線、点、ビルボード、モデル、およびその他のグラフィックス プリミティブを記述し、それらが時間の経過とともにどのように変化するかを指定できます。CZML でリソースを拡張することにより、STK シーンでセンサー (センサー) の検出ダイナミクスを表示するなど、より豊かなシーン効果を実現できます。

ミッションターゲット

この例では、STKPro Stutorial で提供されているサンプル コードを参照してサーバー側で STK シーンを生成し、STK Export CZML プラグインを介して czml 形式のファイル (サーバーにローカルに格納されている) を出力し、クライアントブラウザは czml ファイルを読み込むことでシーンの再現を実現します。

環境とバージョン

  • STK11.6

  • VS2017(C#、.NETFramework 4.8)

  • セシウム-1.99

関連リソース

このシリーズの以前のブログ投稿を参照してください: https://blog.csdn.net/wangyulj/article/details/128914391

実施プロセス

サーバー側のシーン生成

コードは次のとおりです (STK サンプル コードに基づいて注記が追加されます)。

        [WebMethod(Description = "以STK Tutorial场景为例输出czml文件")]
        public void CzmlExport()
        {
            string description = "";  // 计算过程、结果或异常等的描述
            this.m_STKApp = null;
            this.m_STKRoot = null;

            //--------------------------------------------------------
            // 参照STK Pro Tutorial创建场景,并输出czml文件
            //--------------------------------------------------------
            if (!InvokeSTK(out description))
            {
                StkCalCommon.packAndResponse(this.Context, -1, description, "");
                return;
            }

            // 设置场景各计算单位(有可能之前的场景设置不同,最好是重置一遍)
            SetUnits();

            // 设置仿真时间:startTime, stopTime, epoch
            string startTime = "1 Jul 2002 00:00:00.00";
            string stopTime  = "1 Jul 2002 04:00:00.00";
            string epoch     = "1 Jul 2002 00:00:00.00";
            SetSimuTimes(startTime, stopTime, epoch);

            //currently there is no way to set the 2d graphics properties for the scenario listed in the tutorial

            // 创建地面设施
            // AgESTKObjectType Enumeration
            // IAgScenario 接口实现了 IAgStkObject 接口以及 IAgLifetimeInformation 接口
            // 此处用的是 m_STKRoot.CurrentScenario 的 IAgStkObject 接口的 Children 属性的 New() 方法
            // m_STKRoot.CurrentScenario.Children : IAgStkObjectCollection Interface,表示一组STK对象的集合
            IAgFacility baikonur = (IAgFacility)this.m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eFacility, "Baikonur");
            // IAgFacility.UseTerrain:选择是否使用地形数据自动设置(facility)高度
            baikonur.UseTerrain = false;
            // -- AgEPositionType:属于STK Util库,定了7种位置类型:
            // eCartesian - 笛卡尔坐标:根据对象位置向量的 X、Y 和 Z 分量指定的位置,其中 Z 轴指向北极,X 轴穿过 0 度纬度/0 度经度。
            // eCylindrical - 圆柱:根据半径(极坐标)、经度(以度数从 -360.0 度到 +360.0 度测量)和对象位置矢量的 Z 分量指定的位置。
            // eGeocentric - 地心:以纬度(地球表面上子点的球纬度)、经度和高度指定的位置。
            // eGeodeti - 大地测量:根据纬度(参考椭球法线与赤道平面之间的角度)、经度和高度指定的位置。
            // eSpherical - 球面:根据纬度(地球表面子点的球面纬度)、经度和半径(物体距地球中心的距离)指定的位置。
            // ePlanetocentric - 行星中心:根据纬度(地球表面子点的球面纬度)、经度和高度指定的位置。
            // ePlanettodetic - 行星大地测量:根据纬度(参考椭球法线与赤道平面之间的角度)、经度和高度指定的位置。
            // -- 此处用的是 ePlanetodetic,根据维度(参考椭球法线与赤道平面之间的角度)、维度和高度指定位置
            IAgPlanetodetic planetodetic = (IAgPlanetodetic)baikonur.Position.ConvertTo(AgEPositionType.ePlanetodetic);
            planetodetic.Lat = 48.0;
            planetodetic.Lon = 55.0;
            planetodetic.Alt = 0.0;
            baikonur.Position.Assign(planetodetic);

            // 注意在运算中在特定的STK对象(例如IAgFacility)与通用的STK对象(IAgStkObject)之间的转换
            ((IAgStkObject)baikonur).ShortDescription = "Launch Site";
            ((IAgStkObject)baikonur).LongDescription = "Launch site in Kazakhstan. Also known as Tyuratam.";

            // 继续创建两个地面站(设施)
            IAgFacility perth = (IAgFacility)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eFacility, "Perth");
            IAgFacility wallops = (IAgFacility)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eFacility, "Wallops");

            perth.UseTerrain = false;
            planetodetic = (IAgPlanetodetic)perth.Position.ConvertTo(AgEPositionType.ePlanetodetic);
            planetodetic.Lat = -31.0;
            planetodetic.Lon = 116.0;
            planetodetic.Alt = 0;
            perth.Position.Assign(planetodetic);

            ((IAgStkObject)perth).ShortDescription = "Australian Tracking Station";

            wallops.UseTerrain = false;
            planetodetic = (IAgPlanetodetic)wallops.Position.ConvertTo(AgEPositionType.ePlanetodetic);
            planetodetic.Lat = 37.8602;
            planetodetic.Lon = -75.5095;
            planetodetic.Alt = -0.0127878;
            wallops.Position.Assign(planetodetic);

            ((IAgStkObject)wallops).ShortDescription = "NASA Launch Site/Tracking Station";

            // 从现有数据库添加地面设施(示例代码)
            // 执行connct命令示例
            AGI.STKUtil.AgExecCmdResult facDbResult = (AgExecCmdResult)m_STKRoot.ExecuteCommand("GetDirectory / Database Facility");
            string facDataDir = facDbResult[0];     // 取返回结果的第一个元素
            // @符号:可使字符串不必使用转义序列
            string filelocation = facDataDir + @"\stkFacility.fd";
            string command = "ImportFromDB * Facility \"" + filelocation + "\"Class Facility SiteName \"Santiago Station AGO 3 STDN AGO3\" Network \"NASA NEN\" Rename Santiago";
            m_STKRoot.ExecuteCommand(command);
            command = "ImportFromDB * Facility \"" + filelocation + "\"Class Facility SiteName \"White Sands\" Network \"Other\" Rename WhiteSands";
            m_STKRoot.ExecuteCommand(command);

            // 获取刚刚创建的两个 Facility 对象
            IAgFacility santiago = (IAgFacility)m_STKRoot.CurrentScenario.Children["Santiago"];
            IAgFacility whitesands = (IAgFacility)m_STKRoot.CurrentScenario.Children["WhiteSands"];

            // ***.Graphics : IAgFaGraphics,修改地面设置的(显示)颜色
            // 为啥不用 FromArgb 方法之外的其他形式,直接一个 int 参数实在是不直观
            // 可以注释掉下面4行,实际效果比价差,颜色暗,还不如默认的颜色,也可以根据实际效果调整
            //baikonur.Graphics.Color = Color.Lime;
            //perth.Graphics.Color = Color.FromArgb(16777215);
            //wallops.Graphics.Color = Color.FromArgb(13421772);
            //santiago.Graphics.Color = Color.FromArgb(88888);
            //whitesands.Graphics.Color = Color.FromArgb(1234567);

            // 创建 Target 对象,与创建 Facility 对象基本一致
            IAgTarget iceberg = (IAgTarget)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eTarget, "Iceberg");
            iceberg.UseTerrain = false;
            planetodetic = (IAgPlanetodetic)iceberg.Position.ConvertTo(AgEPositionType.ePlanetodetic);
            planetodetic.Lat = 74.91;
            planetodetic.Lon = -74.5;
            planetodetic.Alt = 0.0;
            iceberg.Position.Assign(planetodetic);

            ((IAgStkObject)iceberg).ShortDescription = "Only the tip.";

            // 创建 Ship 对象
            // AgShip类实现了如下接口:IAgGreatArcVehicle, IAgLifetimeInformation, IAgProvideSpatialInfo, IAgShip, IAgStkObject
            IAgShip cruise = (IAgShip)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eShip, "Cruise");
            // 设置路径预报器,SetRouteType()是IAgGreatArcVehicle接口方法
            // 包括AgGroundVehicle, AgAircraft, AgShip等三个COM类(CoClass)实现了 IAgGreatArcVehicle 接口
            // AgEVePropagatorType,因为涵盖了卫星的轨道预报器,有点多,定义了18种,其中大弧预报器用于飞机、船只、地面车辆。
            cruise.SetRouteType(AgEVePropagatorType.ePropagatorGreatArc);
            IAgVePropagatorGreatArc greatArc = (IAgVePropagatorGreatArc)cruise.Route;
            IAgCrdnEventIntervalSmartInterval smartInterval = greatArc.EphemerisInterval;
            // 下面方法的第二个参数没有用 stopTime,而是STK计算模块根据Ship对象的路径及速度(速度应该是一个系统默认值)
            // 计算,根据czml文件的输出结果判断,Ship沿路径点需要5天才能到达目的地,而其他对象的计算时间均约定为4小时,
            // 所以在czml文件的仿真时间中,是取场景中各对象的仿真时间的最大值为
            smartInterval.SetExplicitInterval(startTime, smartInterval.FindStopTime());
            greatArc.Method = AgEVeWayPtCompMethod.eDetermineTimeAccFromVel;

            // 设置 Ship 的路径点
            AddWaypoint(greatArc.Waypoints, 44.1, -8.5, 0.0, .015, 0.0);
            AddWaypoint(greatArc.Waypoints, 51.0, -26.6, 0.0, .015, 0.0);
            AddWaypoint(greatArc.Waypoints, 52.1, -40.1, 0.0, .015, 0.0);
            AddWaypoint(greatArc.Waypoints, 60.2, -55.0, 0.0, .015, 0.0);
            AddWaypoint(greatArc.Waypoints, 68.2, -65.0, 0.0, .015, 0.0);
            AddWaypoint(greatArc.Waypoints, 72.5, -70.1, 0.0, .015, 0.0);
            AddWaypoint(greatArc.Waypoints, 74.9, -74.5, 0.0, .015, 0.0);

            // AgEVeAttitude(姿态类型)定义了两个值:eAttitudeRealtime, eAttitudeStandard
            // 设置大弧预报器的各参数,然后进行路径计算
            cruise.SetAttitudeType(AgEVeAttitude.eAttitudeStandard);
            IAgVeRouteAttitudeStandard attitude = (IAgVeRouteAttitudeStandard)cruise.Attitude;
            attitude.Basic.SetProfileType(AgEVeProfile.eProfileECFVelocityAlignmentWithRadialConstraint);
            cruise.Graphics.WaypointMarker.IsWaypointMarkersVisible = true;
            cruise.Graphics.WaypointMarker.IsTurnMarkersVisible = true;
            greatArc.Propagate();    // 轨道预报(计算)

            //===========================================================================
            // 创建卫星,TDRS: Tracking & Data Relay Satellite
            // IAgSatellite 其实只有两个接口方法:SetAttitudeType, SetPropagatorType,分别指定姿态和预报器类型
            // 相比 IAgShip,IAgSatellite 仅实现了三个接口IAgStkObject,IAgLifetimeInformation,IAgProvideSpatialInfo
            IAgSatellite tdrs = (IAgSatellite)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eSatellite, "TDRS");
            // 设置轨道预报器(类型),二体(运动)预报器的应用实例代码
            tdrs.SetPropagatorType(AgEVePropagatorType.ePropagatorTwoBody);
            // 二体问题,或者开普勒运动,预报器只考虑来自地球的引力,将其建模为一个质点
            IAgVePropagatorTwoBody twobody = (IAgVePropagatorTwoBody)tdrs.Propagator;

            // IAgOrbitState:系统定义了7种 Orbit State(轨道状态的坐标类型):
            // Cartesian, Classical, Delaunay, Equinoctial, Geodetic, MixedSpherical, Spherical
            IAgOrbitStateClassical classical = (IAgOrbitStateClassical)twobody.InitialState.Representation.ConvertTo(AgEOrbitStateType.eOrbitStateClassical);
            classical.CoordinateSystemType = AgECoordinateSystem.eCoordinateSystemJ2000;
            smartInterval = twobody.EphemerisInterval;
            smartInterval.SetExplicitInterval(startTime, stopTime);
            twobody.Step = 60;    // 秒(s)
            // AgEClassicalLocation预定义值包括:
            //     eLocationArgumentOfLatitude - 使用纬度参数指定航天器位置。
            //     eLocationExcentricAnomaly - 使用 Eccentric Anomaly 指定航天器位置。
            //     eLocationMeanAnomaly - 使用平均异常来指定航天器位置。
            //     eLocationTimePastAN - 使用经过升交点的时间指定航天器位置。
            //     eLocationTimePastPerigee - 使用 Time Past Perigee 指定航天器位置。
            //     eLocationTrueAnomaly - 使用 True Anomaly 指定航天器位置。
            classical.LocationType = AgEClassicalLocation.eLocationTrueAnomaly;
            IAgClassicalLocationTrueAnomaly trueAnomaly = (IAgClassicalLocationTrueAnomaly)classical.Location;
            // ture anomaly: 真近点角
            trueAnomaly.Value = 178.845262;

            // 利用轨道周期和偏心率确定轨道形状
            classical.SizeShapeType = AgEClassicalSizeShape.eSizeShapePeriod;
            // IAgClassicalSizeShapePeriod:使用周期和偏心率指定(卫星的)轨道大小和形状
            IAgClassicalSizeShapePeriod period = (IAgClassicalSizeShapePeriod)classical.SizeShape;
            // Eccentricity: 偏心率,离心率
            period.Eccentricity = 0.0;
            // 轨道周期,基于假定的二体运动的轨道周期
            period.Period = 86164.090540;
            // classical.Orientation: IAgClassicalOrientation Interface
            // 近地点角:从升交点到在卫星运动方向和轨道平面中测量的偏心矢量(轨道最低点)的角度
            classical.Orientation.ArgOfPerigee = 0.0;
            // 轨道倾角
            classical.Orientation.Inclination = 0.0;
            // 升交点类型包括:LAN(Longitude of Ascending Node,升交点经度), RAAN(升交点赤经)
            // 升交点经度:卫星从南向北穿过惯性赤道的地球固定经度(the Earth-fixed longitude where the satellite crosses the inertial equator form south to north)
            // LAN : the Earth-fixed longitude where the satellite crosses the inertial equator form south to north
            // RAAN: the angle from the inertial X axis to the ascending node measured in a right-handed sense about the inertial Z axis in the equatorial plane
            classical.Orientation.AscNodeType = AgEOrientationAscNode.eAscNodeLAN;
            IAgOrientationAscNodeLAN lan = (IAgOrientationAscNodeLAN)classical.Orientation.AscNode;
            // 升交点经度
            lan.Value = 259.999982;

            twobody.InitialState.Representation.Assign(classical);
            // 执行轨道计算(预报)
            twobody.Propagate();

            // 从数据库(文件)创建卫星
            AGI.STKUtil.AgExecCmdResult satDbResult = (AgExecCmdResult)m_STKRoot.ExecuteCommand("GetDirectory / Database Satellite");
            string satDataDir = satDbResult[0];
            filelocation = satDataDir + @"\stkSatDB.sd";
            // STK示例代码此处有一个bug,Rename的参数“TDRS 3”与后续代码实际使用的名称不一致,少了一个下划线
            // 在CustomApplications项目中的代码是正确的(Automation中的代码有bug)
            //command = "ImportFromDB * Satellite \"" + filelocation + "\" Rename \"TDRS 3\" Propagate On CommonName \"TDRS 3\"";
            command = "ImportFromDB * Satellite \"" + filelocation + "\" Rename TDRS_3 Propagate On CommonName \"TDRS 3\"";
            m_STKRoot.ExecuteCommand(command);
            // 获取刚刚从数据库文件创建的卫星对象
            IAgSatellite tdrsC = (IAgSatellite)m_STKRoot.CurrentScenario.Children["TDRS_3"];
            // 需要重新计算(预报)报道,用的是SGP4轨道预报器(简化的通用摄动预报器,与TLE一起使用)
            IAgVePropagatorSGP4 sgp4 = (IAgVePropagatorSGP4)tdrsC.Propagator;
            smartInterval = sgp4.EphemerisInterval;
            smartInterval.SetExplicitInterval(startTime, stopTime);

            // 创建ERS(Earth Resources Satellite)卫星
            IAgSatellite ers1 = (IAgSatellite)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eSatellite, "ERS1");
            // j4: J4摄动(二阶)预报器,考虑了由于地球扁率引起的轨道要素的长期变化
            ers1.SetPropagatorType(AgEVePropagatorType.ePropagatorJ4Perturbation);
            IAgVePropagatorJ4Perturbation j4 = (IAgVePropagatorJ4Perturbation)ers1.Propagator;
            smartInterval = j4.EphemerisInterval;
            smartInterval.SetExplicitInterval(startTime, stopTime);
            j4.Step = 60.00;

            // J4预报器的参数设置还蛮多的
            IAgOrbitState j4Orb = j4.InitialState.Representation as IAgOrbitState;
            j4Orb.Epoch = startTime;
            classical = (IAgOrbitStateClassical)j4.InitialState.Representation.ConvertTo(AgEOrbitStateType.eOrbitStateClassical);
            classical.CoordinateSystemType = AgECoordinateSystem.eCoordinateSystemJ2000;
            // ture anomaly: 真近点角
            classical.LocationType = AgEClassicalLocation.eLocationTrueAnomaly;
            trueAnomaly = (IAgClassicalLocationTrueAnomaly)classical.Location;
            trueAnomaly.Value = 0.0;
            // 通过指定半长轴(Semimajor Axis)和偏心率以确定轨道形状
            classical.SizeShapeType = AgEClassicalSizeShape.eSizeShapeSemimajorAxis;
            IAgClassicalSizeShapeSemimajorAxis semi = (IAgClassicalSizeShapeSemimajorAxis)classical.SizeShape;
            semi.SemiMajorAxis = 7163.14;   // 半长轴
            semi.Eccentricity = 0.0;    // 偏心率/离心率
            classical.Orientation.ArgOfPerigee = 0.0;   // 近地点角
            classical.Orientation.AscNodeType = AgEOrientationAscNode.eAscNodeLAN;
            lan = (IAgOrientationAscNodeLAN)classical.Orientation.AscNode;
            lan.Value = 99.38;  // 升交点经度
            classical.Orientation.Inclination = 98.50;  // 轨道倾角

            j4.InitialState.Representation.Assign(classical);
            j4.Propagate();

            // IAgSaGraphics Interface : ers1.Graphics,卫星的2D图形属性
            // IAgVeGfxPasses Interface : ers1.Graphics.Passes,用于设置卫星轨迹显示的接口
            // 看示例代码中的语句,应该是设置了Both,就没有必要再设置Descending,前一句代码多余(冗余)
            // 如果只是需要生成数据报告,则可以简化或忽略对2D或3D属性的设置
            ers1.Graphics.Passes.VisibleSides = AgEVeGfxVisibleSides.eVisibleSidesDescending;
            ers1.Graphics.Passes.VisibleSides = AgEVeGfxVisibleSides.eVisibleSidesBoth;

            // 新建一个空间站(Shuttle),使用J4预报器计算轨道
            // 参考上一卫星创建的注释及说明
            IAgSatellite shuttle = (IAgSatellite)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eSatellite, "Shuttle");
            shuttle.SetPropagatorType(AgEVePropagatorType.ePropagatorJ4Perturbation);
            j4 = (IAgVePropagatorJ4Perturbation)shuttle.Propagator;
            smartInterval = j4.EphemerisInterval;
            // 此处与原代码有不同,原代码的 stopTime 仅计算到 3 点
            smartInterval.SetExplicitInterval(startTime, stopTime);
            j4.Step = 60.00;

            j4Orb = j4.InitialState.Representation as IAgOrbitState;
            j4Orb.Epoch = startTime;
            classical = (IAgOrbitStateClassical)j4.InitialState.Representation.ConvertTo(AgEOrbitStateType.eOrbitStateClassical);
            classical.CoordinateSystemType = AgECoordinateSystem.eCoordinateSystemJ2000;
            classical.LocationType = AgEClassicalLocation.eLocationTrueAnomaly;
            trueAnomaly = (IAgClassicalLocationTrueAnomaly)classical.Location;
            trueAnomaly.Value = 0.0;    // 真近点角
            // Size Shape Type与前一创建实例不一样
            //     eSizeShapeAltitude - Apogee and Perigee Altitude(远地点和近地点高度).
            //     eSizeShapeMeanMotion - Mean Motion and Eccentricity(平均运动和离心率.
            //     eSizeShapePeriod - Period and Eccentricity(周期和偏心率).
            //     eSizeShapeRadius - Apogee and Perigee Radius(远地点和近地点半径).
            //     eSizeShapeSemimajorAxis - Semimajor Axis and Eccentricity(半长轴和偏心率).
            // 通过指定远地点和近地点高度确定轨道形状
            classical.SizeShapeType = AgEClassicalSizeShape.eSizeShapeAltitude;
            IAgClassicalSizeShapeAltitude altitude = (IAgClassicalSizeShapeAltitude)classical.SizeShape;
            altitude.ApogeeAltitude = 370.4;    // 远地点高度
            altitude.PerigeeAltitude = 370.4;   // 近地点高度
            classical.Orientation.ArgOfPerigee = 0.0;   // 近地点角
            classical.Orientation.AscNodeType = AgEOrientationAscNode.eAscNodeLAN;
            lan = (IAgOrientationAscNodeLAN)classical.Orientation.AscNode;
            lan.Value = -151.0;  // 升交点经度
            classical.Orientation.Inclination = 28.5;  // 轨道倾角

            j4.InitialState.Representation.Assign(classical);
            j4.Propagate();

            // Modify Shuttle Contours(轮廓/等高线),这个属性估计czml不会输出
            shuttle.Graphics.SetAttributesType(AgEVeGfxAttributes.eAttributesBasic);
            // IAgVeGfxAttributesOrbit : 设置卫星2D属性的接口,本接口又借助接口IAgVeGfxAttributesBasic(的实现)提供相关功能
            IAgVeGfxAttributesOrbit orbitgfx = (IAgVeGfxAttributesOrbit)shuttle.Graphics.Attributes;
            orbitgfx.Line.Style = AgELineStyle.eDashed;
            // 下面这个关键字‘Plus’没有预定义枚举类型,就怕这种参数,最好是别用到
            orbitgfx.MarkerStyle = "Plus";

            // contours : 轮廓线/等高线,这个等高线的设置后的效果在图中没有看出来
            // 轮廓线的设置在czml文件也未输出
            IAgVeGfxElevContours contours = (IAgVeGfxElevContours)shuttle.Graphics.ElevContours;
            IAgVeGfxElevationsCollection elevations = contours.Elevations;
            elevations.RemoveAll();
            elevations.AddLevelRange(0, 50, 10);

            for (int i = 0; i < elevations.Count; i++)
            {
                IAgVeGfxElevationsElement elem = elevations[i];
                elem.DistanceVisible = false;
                elem.LineStyle = AgELineStyle.eDotDashed;
                elem.LineWidth = AgELineWidth.e3;
            }

            // 下面几条语句不起作用,在本例中忽略
            //contours.IsVisible = true;
            //contours.Fill = true; 此版本没有Fill属性(可设置)
            //contours.FillTranslucency = 80.0;

            //=========================================================================
            //Again we don't have the capability in OM to handle a second graphics window and modify it's properties
            // 创建面目标(AreaTarget)
            IAgAreaTarget searchArea = (IAgAreaTarget)m_STKRoot.CurrentScenario.Children.New(AgESTKObjectType.eAreaTarget, "SearchArea");
            // 设置AreaTarget的2D属性
            IAgATGraphics atGfx = searchArea.Graphics;
            atGfx.MarkerStyle = "None";
            atGfx.Inherit = false;
            atGfx.LabelVisible = false;
            atGfx.CentroidVisible = false;

            searchArea.UseTerrainData = false;
            searchArea.AutoCentroid = false;
            // 有另种方式指定AreaTarget的边界:
            //     eEllipse - 椭圆
            //     ePattern - 类似于多边形,以一组点坐标(经纬度)定义边界
            searchArea.AreaType = AgEAreaType.ePattern;
            IAgAreaTypePatternCollection patterns = (IAgAreaTypePatternCollection)searchArea.AreaTypeData;
            patterns.Add(78.4399, -77.6125);
            patterns.Add(77.7879, -71.1578);
            patterns.Add(74.5279, -69.0714);
            patterns.Add(71.6591, -69.1316);
            patterns.Add(70.0291, -70.8318);
            patterns.Add(71.9851, -76.3086);

            // Spherical : 球面坐标定义:维度、经度、球半径(此处为地球半径)
            // 此处指定的是AreaTarget的中心?难道不应该自动计算吗?
            // 经往回看,此处的坐标是前面目标对象(Target对象)Iceberg的坐标
            IAgSpherical sphere = (IAgSpherical)searchArea.Position.ConvertTo(AgEPositionType.eSpherical);
            sphere.Lat = 74.9533;
            sphere.Lon = -74.5482;
            sphere.Radius = 6358.186790;
            searchArea.Position.Assign(sphere);

            // 访问计算,从ers1 到 searchArea
            IAgStkAccess access = ((IAgStkObject)ers1).GetAccessToObject((IAgStkObject)searchArea);
            access.ComputeAccess();

            // 最怕的就是这种指定的字符串,而不是预定义的字符串,其他的如何知道?
            IAgDataPrvInterval interval = (IAgDataPrvInterval)access.DataProviders["Access Data"];

            // IAgDrResult : Provides methods to access the results returned by the data provider
            IAgDrResult result = (IAgDrResult)interval.Exec(startTime, stopTime);

            //with the result returned, the user can use the data any way they prefer.
            // 此处示例代码省略了关于如何使用数据

            // 清除当前的Access数据
            //access.RemoveAccess();

            // 给卫星(ERS1)添加一个传感器
            IAgSensor horizon = (IAgSensor)m_STKRoot.CurrentScenario.Children["ERS1"].Children.New(AgESTKObjectType.eSensor, "Horizon");
            // eSnSimpleConic : 简单圆锥:由指定的圆锥角定义
            // AgESnPattern中定义了 7 种类型的传感器(天线)模式
            horizon.SetPatternType(AgESnPattern.eSnSimpleConic);
            IAgSnSimpleConicPattern simpleConic = (IAgSnSimpleConicPattern)horizon.Pattern;
            simpleConic.ConeAngle = 90; // 圆锥角
            // AgESnPointing中定义了 9 种类型的(传感器天线)跟踪模式
            horizon.SetPointingType(AgESnPointing.eSnPtFixed);
            IAgSnPtFixed fixedPt = (IAgSnPtFixed)horizon.Pointing;
            // azEl : 方位角/仰角(az:Azimuth, El:Elevation)
            IAgOrientationAzEl azEl = (IAgOrientationAzEl)fixedPt.Orientation.ConvertTo(AgEOrientationType.eAzEl);
            azEl.Elevation = 90;
            azEl.AboutBoresight = AgEAzElAboutBoresight.eAzElAboutBoresightRotate;
            fixedPt.Orientation.Assign(azEl);

            //removing the ers1 elevcontours from the 2d window
            // 移除 ERS1 有关轮廓线的设置(设置为不可见)
            // 此代码对于 czml 输出没有影响
            contours.IsVisible = false;

            // 继续给卫星(ERS1)添加另一个传感器
            IAgSensor downlink = (IAgSensor)m_STKRoot.CurrentScenario.Children["ERS1"].Children.New(AgESTKObjectType.eSensor, "Downlink");

            // eSnHalfPower : 半功率(Half Power),模拟抛物面天线
            downlink.SetPatternType(AgESnPattern.eSnHalfPower);
            IAgSnHalfPowerPattern halfpower = (IAgSnHalfPowerPattern)downlink.Pattern;
            halfpower.Frequency = .85;  // 频率
            halfpower.AntennaDiameter = 1.0;    // 天线口径(m)

            // 设置传感器的目标对象,可与前面的 eSnPtFixed 比较
            downlink.SetPointingType(AgESnPointing.eSnPtTargeted);
            IAgSnPtTargeted targeted = (IAgSnPtTargeted)downlink.Pointing;
            // Boresight : 视轴类型
            targeted.Boresight = AgESnPtTrgtBsightType.eSnPtTrgtBsightTracking;
            // 可一次指定多个 targets
            IAgSnTargetCollection targets = targeted.Targets;
            targets.Add("Facility/Baikonur");
            targets.Add("Facility/WhiteSands");
            targets.Add("Facility/Perth");
            targets.AddObject((IAgStkObject)santiago);
            targets.Add(((IAgStkObject)wallops).Path);

            // 为地面设施(地面站Wallops)创建一个传感器
            IAgSensor fiveDegElev = (IAgSensor)m_STKRoot.CurrentScenario.Children["Wallops"].Children.New(AgESTKObjectType.eSensor, "FiveDegElev");
            // eSnComplexConic : 复杂圆锥,二次曲线,由指定的内半角和外半角以及最小和最大时钟角定义
            fiveDegElev.SetPatternType(AgESnPattern.eSnComplexConic);
            IAgSnComplexConicPattern complexConic = (IAgSnComplexConicPattern)fiveDegElev.Pattern;
            complexConic.InnerConeHalfAngle = 0;    // 内半角
            complexConic.OuterConeHalfAngle = 85;   // 外半角
            complexConic.MinimumClockAngle = 0;     // 最小时钟角
            complexConic.MaximumClockAngle = 360;   // 最大时钟角

            // eSnPtFixed : 设置步骤与前述同
            fiveDegElev.SetPointingType(AgESnPointing.eSnPtFixed);
            fixedPt = (IAgSnPtFixed)fiveDegElev.Pointing;
            azEl = (IAgOrientationAzEl)fixedPt.Orientation.ConvertTo(AgEOrientationType.eAzEl);
            azEl.Elevation = 90;
            azEl.AboutBoresight = AgEAzElAboutBoresight.eAzElAboutBoresightRotate;
            fixedPt.Orientation.Assign(azEl);

            // Graphics相关的设置与2D显示有关
            fiveDegElev.Graphics.Projection.DistanceType = AgESnProjectionDistanceType.eConstantAlt;
            IAgSnProjDisplayDistance dispDistance = (IAgSnProjDisplayDistance)fiveDegElev.Graphics.Projection.DistanceData;
            dispDistance.Max = 785.248;
            dispDistance.Min = 0;
            dispDistance.NumberOfSteps = 1;

            // 重新进行轨道计算?是的,重新计算了卫星 ERS1 的轨道
            j4 = (IAgVePropagatorJ4Perturbation)ers1.Propagator;
            smartInterval = j4.EphemerisInterval;
            // 参数与前述不同,前面直接用的 startTime,此处为 FindStartTime()
            // 第二个参数为啥是前面的 startTime ?哦,不是,是第二天,计算了 24h
            smartInterval.SetExplicitInterval(smartInterval.FindStartTime(), "2 Jul 2002 00:00:00.000");
            j4.Propagate();

            // 定制了计算时间段及其显示(属性)
            ers1.Graphics.SetAttributesType(AgEVeGfxAttributes.eAttributesCustom);
            IAgVeGfxAttributesCustom customAtt = (IAgVeGfxAttributesCustom)ers1.Graphics.Attributes;
            IAgVeGfxInterval gfxInterval = customAtt.Intervals.Add("1 Jul 2002 11:30:00.000", "1 Jul 2002 12:00:00.000");
            gfxInterval.GfxAttributes.Color = Color.FromArgb(15649024); //EEC900
            gfxInterval.GfxAttributes.IsVisible = true;
            gfxInterval.GfxAttributes.Inherit = true;

            gfxInterval = customAtt.Intervals.Add("1 Jul 2002 23:30:00.000", "1 Jul 2002 24:00:00.000");
            gfxInterval.GfxAttributes.Color = Color.FromArgb(11680494); //B23AEE
            gfxInterval.GfxAttributes.IsVisible = true;
            gfxInterval.GfxAttributes.Inherit = true;

            // 设置(卫星 ERS1 的追踪目标),此处设置的似乎是 Graphics 属性,与真正的Access计算无关
            // IAgSaGraphics : ers1.Graphics
            // AgEVeGfxAttributes.eAttributesAccess : Display based on access periods.
            ers1.Graphics.SetAttributesType(AgEVeGfxAttributes.eAttributesAccess);
            IAgVeGfxAttributesAccess gfxAccess = (IAgVeGfxAttributesAccess)ers1.Graphics.Attributes;

            gfxAccess.AccessObjects.Add("Facility/Wallops");
            gfxAccess.AccessObjects.Add("Facility/Santiago");
            gfxAccess.AccessObjects.Add("Facility/Baikonur");
            gfxAccess.AccessObjects.Add("Facility/Perth");
            gfxAccess.AccessObjects.Add(((IAgStkObject)whitesands).Path);

            IAgVeGfxAttributesOrbit orbitGfx = (IAgVeGfxAttributesOrbit)gfxAccess.NoAccess;
            orbitGfx.IsVisible = true;
            orbitGfx.Inherit = false;
            orbitGfx.IsGroundMarkerVisible = false;
            orbitGfx.IsOrbitMarkerVisible = false;

            // horizon是卫星 ERS1 的传感器
            IAgDisplayTm horizonDispTm = (IAgDisplayTm)horizon;
            horizonDispTm.SetDisplayStatusType(AgEDisplayTimesType.eDuringAccess);
            IAgDuringAccess duringAccess = (IAgDuringAccess)horizonDispTm.DisplayTimesData;

            IAgObjectLinkCollection accessObjects = duringAccess.AccessObjects;
            accessObjects.Add("Facility/Wallops");
            accessObjects.Add("Facility/Santiago");
            accessObjects.Add("Facility/Baikonur");
            accessObjects.AddObject((IAgStkObject)perth);
            accessObjects.Add(((IAgStkObject)whitesands).Path);

            // 可见性计算,from(卫星ERS1的)传感器 horizon 到地面站 baikonur,并没有计算到所有对象的Access!
            // 为什么在完成了Access计算之后再进行约束设置?
            access = ((IAgStkObject)horizon).GetAccessToObject((IAgStkObject)baikonur);
            access.ComputeAccess();

            IAgAccessCnstrMinMax minMax = (IAgAccessCnstrMinMax)horizon.AccessConstraints.AddConstraint(AgEAccessConstraints.eCstrSunElevationAngle);
            minMax.EnableMin = true;
            minMax.Min = 10;
            //minMax.Min = 5;
            //minMax.Min = 0;
            //minMax.Min = 15;
            //minMax.Min = 20;

            horizon.AccessConstraints.RemoveConstraint(AgEAccessConstraints.eCstrSunElevationAngle);

            minMax = (IAgAccessCnstrMinMax)horizon.AccessConstraints.AddConstraint(AgEAccessConstraints.eCstrRange);
            minMax.EnableMax = true;
            minMax.Max = 2000;
            //minMax.Max = 1500;
            //minMax.Max = 1000;
            //minMax.Max = 500;

            horizon.AccessConstraints.RemoveConstraint(AgEAccessConstraints.eCstrRange);

            // 清除Access计算
            //access.RemoveAccess();

            // 重置仿真时间(到开始时刻)
            ((IAgAnimation)this.m_STKRoot).Rewind();

            //---------------------------------------------------------------------------
            // export CZML
            // 语法:ExportCZML <ScenarioPath> "<OutputFilePath>" {3D Model Server URL}
            // 要点:1)如果目标文件已经存在,则STK会覆盖现有文件;
            //       2)必须指定{3D Model Server URL},否则失败,可以在后续对czml文件执行处理替换
            filelocation = StkCalCommon.g_czmlLocalPath + "stkprotutorial.czml";
            command = "ExportCZML * \"" + filelocation + "\" " + @"http://assets.agi.com/models/";
            m_STKRoot.ExecuteCommand(command);
            //---------------------------------------------------------------------------

            // 关闭场景,释放资源
            ReleaseSTKR();

            string czmlURL = StkCalCommon.g_czmlURL + "stkprotutorial.czml";
            StkCalCommon.packAndResponse(this.Context, 0, "成功执行操作,生成CZML文件。", czmlURL);
        }

コード内のその他の関連メソッドのリストは次のとおりです。

STKプロセスの統一初期化管理(InvokeSTKメソッド)

        // 获取或创建STK进程,并根据需要新建场景
        public bool InvokeSTK(out string description, bool newScenario = true)
        {
            string logging = "---- " + DateTime.Now + " ----\n";
            logging += "STK应用初始化。\n";
            this.m_STKApp = null;
            this.m_STKRoot = null;
            description = "";
            // 获取或创建STK应用(AgUiApplication对象)
            try
            {
                logging += "Looking for an instance of STK...\n";
                // 获取已有STK运行实例
                this.m_STKApp = Marshal.GetActiveObject("STK11.Application") as AgUiApplication;
            }
            catch (System.Runtime.InteropServices.COMException ex1)
            {
                logging += "Failed in looking for an instance of STK.\n";
                logging += ex1.Message + "\n";
                // 获取已有STK实例失败,创建一个新的STK实例
                Guid clsID = typeof(AgUiApplicationClass).GUID;
                Type oType = Type.GetTypeFromCLSID(clsID);
                try
                {
                    logging += "Try to create an instance of STK...\n";
                    StkCalCommon.loggingToFile(logging);
                    this.m_STKApp = Activator.CreateInstance(oType) as AgUiApplication;

                    logging += "Try to load STK personality.\n";
                    StkCalCommon.loggingToFile(logging);
                    // 获取用户设置(此过程应该是执行了有关license的检测)
                    this.m_STKApp.LoadPersonality("STK");
                }
                catch (System.Runtime.InteropServices.COMException ex2)
                {
                    logging += "Failed in creating STK instance or loading STK personality.\n";
                    logging += ex2.Message + "\n";
                    StkCalCommon.loggingToFile(logging);
                    this.m_STKApp = null;
                    description = "获取或创建STK应用实例失败1。\n" + ex2.Message;
                    return false;
                }
            }
            // 加载STK Root(IAgStkObjectRoot接口对象)
            if (!(this.m_STKApp is null))
            {
                try
                {
                    logging += "Loading STK root object (IAgStkObjectRoot).\n";
                    this.m_STKRoot = (IAgStkObjectRoot)this.m_STKApp.Personality2;
                    description = "成功创建STK用户应用并获取STK Root对象。";
                }
                catch (Exception ex3)
                {
                    logging += "加载STK Root Object失败。\n";
                    logging += ex3.Message + "\n";
                    StkCalCommon.loggingToFile(logging);
                    description = "加载STK Root Object失败。\n" + ex3.Message;
                    Marshal.ReleaseComObject(this.m_STKApp);
                    return false;
                }
            }

            if ((this.m_STKApp is null) || (this.m_STKRoot is null))
            {
                // 未能初始化STK应用
                logging += "未能初始化STK应用。\n";
                StkCalCommon.loggingToFile(logging);
                description = "未能初始化STK应用。";
                return false;
            }

            logging += "成功获取或创建了STK应用(AgUiApplication),并获取STK Root对象(IAgStkObjectRoot).\n";
            StkCalCommon.loggingToFile(logging);

            if (newScenario)
            {
                // 创建场景
                // 关闭当前(可能有的)场景
                this.m_STKRoot.CloseScenario();
                // 新建场景
                this.m_STKRoot.NewScenario(this.defualtScenName);
            }

            return true;
        }

その他の方法:

       // 释放STK相关进程(资源)
        public void ReleaseSTKR(bool closeSecenario = true)
        {
            // 关闭场景
            this.m_STKRoot.CloseScenario();
            // 退出并关闭STK应用(可选)
            Marshal.ReleaseComObject(this.m_STKRoot);
            Marshal.ReleaseComObject(this.m_STKApp);
            this.m_STKApp = null;
            this.m_STKRoot = null;
        }
        // 设置当前场景单位
        private void SetUnits()
        {
            IAgUnitPrefsDimCollection dimensions = this.m_STKRoot.UnitPreferences;
            // 首先重置,然后设置
            dimensions.ResetUnits();
            dimensions.SetCurrentUnit("DateFormat", "UTCG");
            dimensions.SetCurrentUnit("DistanceUnit", "km");
            dimensions.SetCurrentUnit("TimeUnit", "sec");
            dimensions.SetCurrentUnit("AngleUnit", "deg");
            dimensions.SetCurrentUnit("MassUnit", "kg");
            dimensions.SetCurrentUnit("PowerUnit", "dbw");
            dimensions.SetCurrentUnit("FrequencyUnit", "ghz");
            dimensions.SetCurrentUnit("SmallDistanceUnit", "m");
            dimensions.SetCurrentUnit("latitudeUnit", "deg");
            dimensions.SetCurrentUnit("longitudeunit", "deg");
            dimensions.SetCurrentUnit("DurationUnit", "HMS");
            dimensions.SetCurrentUnit("Temperature", "K");
            dimensions.SetCurrentUnit("SmallTimeUnit", "sec");
            dimensions.SetCurrentUnit("RatioUnit", "db");
            dimensions.SetCurrentUnit("rcsUnit", "dbsm");
            dimensions.SetCurrentUnit("DopplerVelocityUnit", "m/s");
            dimensions.SetCurrentUnit("Percent", "unitValue");
        }
        // 设置仿真时间
        // 参数:UTCG格式的字符串
        private void SetSimuTimes(string startTime, string stopTime, string epoch)
        {
            // 另外还可以通过接口方法 SetTimePeriod()设置
            IAgScenario scene = (IAgScenario)this.m_STKRoot.CurrentScenario;
            scene.StartTime = startTime;
            scene.StopTime = stopTime;
            scene.Epoch = epoch;
        }
        private void AddWaypoint(IAgVeWaypointsCollection waypoints, object Lat, object Lon, double Alt, double Speed, double tr)
        {
            IAgVeWaypointsElement elem = waypoints.Add();
            elem.Latitude = Lat;
            elem.Longitude = Lon;
            elem.Altitude = Alt;
            elem.Speed = Speed;
            elem.TurnRadius = tr;
        }

コードの説明:

コード内の変数は、次のように定義された m_STKApp および m_STKRoot クラスのグローバル変数です。

    public class StkServ : System.Web.Services.WebService
    {
        public AgUiApplication m_STKApp { get; set; }
        public IAgStkObjectRoot m_STKRoot { get; set; }
        private string defualtScenName = "Demo";
……

STKProTutorial インスタンス作成シーンのプロセス

  • STK アプリケーション (プロセス) インスタンスを取得または作成します。

  • 単位を設定します (各初期化シーンの前に、実際の状況に応じて各計算単位を設定することをお勧めします)。

  • シミュレーション時間を設定します。

  • Children.New() メソッドを介して地上施設 (Facility) を作成します。

  • STK によってインストールされたローカル データベース ファイルから地上施設を作成します。

  • シーンで検索するターゲット (ターゲット) オブジェクト、ターゲット (アイスバーグ) を作成します。

  • Ship オブジェクトを作成し、大弧予測器 ( ePropagatorGreatArc ) を使用して船の軌道を計算します。

  • 衛星の作成 (TDRS) では、2 体 (モーション) 予測子 ( ePropagatorTwoBody ) を使用して衛星の軌道を計算する方法を示します。

  • STK データベース ファイルから衛星 (TDRS_3) を読み込んで作成し、SGP4 軌道予測子を使用して衛星軌道を計算します (sgp4.Propagate() メソッドは実際にはコードで実行されませんが、出力には依然として(既存のデータベース ファイルからのものなので、衛星は読み込まれますか? または軌道計算はデフォルトで実行されますか?)

  • 衛星 (ERS1) を作成します。これは、軌道予測 (計算) に J4 摂動 (2 次) 予測子を使用して、エリア検索を示すシーンの主要な衛星です。

  • 実際には衛星オブジェクト (eSatellite) である宇宙ステーション (Shuttle) を作成し、J4 予測子を使用して軌道を計算し、宇宙ステーションの 2 次元表示に複雑なアウトラインを設定します。 STK インターフェイス、および出力 CZML ファイル に関連する表示データはありません。

  • 検索エリアを表すエリア ターゲット (AreaTarget) を作成し、ePattern パターンを介して検索エリアを定義します。

  • 衛星 ERS1 からサーチ エリアへのアクセス計算を実行します。

  • サテライト ERS1 に 2 つのセンサーを追加します。1 つはアップリンク (固定ポインティング) 用、もう 1 つはダウンリンク (追跡モード) 用です。

  • 地上局 Wallops にセンサー (固定ポインティング) を追加します。

  • ERS1 の軌道を再計算し、計算期間は 24 時間で、異なる期間の表示特性をカスタマイズします。

  • センサ Horizo​​n (衛星 ERS1 の) から地上施設バイコヌールへのアクセス データの計算。

最後に、コマンド コマンドを実行して CZML ファイルを出力します。コードは次のようになります (上記のコード行 524 ~ 526)。

      //---------------------------------------------------------------
      // export CZML
      // 语法:ExportCZML <ScenarioPath> "<OutputFilePath>" {3D Model Server URL}
      // 要点:1)如果目标文件已经存在,则STK会覆盖现有文件;
      //       2)必须指定{3D Model Server URL},否则失败,可以在后续对czml文件执行处理替换
      filelocation = StkCalCommon.g_czmlLocalPath + "stkprotutorial.czml";
      command = "ExportCZML * \"" + filelocation + "\" " + @"http://assets.agi.com/models/";
      m_STKRoot.ExecuteCommand(command);
      //-----------------------------------------------------------------

テスト後、「ExportCZML」コマンドの最後のパラメーターを指定する必要があります。これは、デフォルトの 3D モデルのアドレスです。czml ファイルが生成された後、アプリケーションの実際の構成に従ってデフォルトのソースを置き換えることができます。

生成された czml ファイルのサイズは約 2.6M です。

結果の CZML ファイルについて

CZML ファイルの導入に関しては、多くのネットワーク リソースがあり、自分で検索できます. この記事では、参照用に CSDN ブログ投稿のみをリストします.

セシウム学習のための CZML の使用: https://blog.csdn.net/Gua_guagua/article/details/125024376

シミュレーション時間

コードで指定されたシミュレーション時間は 4 時間です。コードは次のとおりです: (注: SetSimuTimes メソッドを含む)

            // 设置仿真时间:startTime, stopTime, epoch
            string startTime = "1 Jul 2002 00:00:00.00";
            string stopTime  = "1 Jul 2002 04:00:00.00";
            string epoch     = "1 Jul 2002 00:00:00.00";
            SetSimuTimes(startTime, stopTime, epoch);

        // 设置仿真时间
        // 参数:UTCG格式的字符串
        private void SetSimuTimes(string startTime, string stopTime, string epoch)
        {
            // 另外还可以通过接口方法 SetTimePeriod()设置
            IAgScenario scene = (IAgScenario)this.m_STKRoot.CurrentScenario;
            scene.StartTime = startTime;
            scene.StopTime = stopTime;
            scene.Epoch = epoch;
        }

CZML ファイルの実際の出力のシミュレーション時間は 4 日以上です。czml ファイルによって出力される最初の JSON 要素のグローバル設定を参照してください。

  {
    "id":"document",
    "name":"Demo",
    "version":"1.0",
    "clock":{
      "interval":"2002-07-01T00:00:00Z/2002-07-05T08:01:42.9280226419796Z",
      "currentTime":"2002-07-01T00:00:00Z",
      "multiplier":600,
      "range":"LOOP_STOP",
      "step":"SYSTEM_CLOCK_MULTIPLIER"
    }
  },
……

コード分​​析によると、出力 CZML ファイルのシミュレーション時間は、シーン内の各オブジェクトの最大シミュレーション時間出力に基づいています.この例のシミュレーション時間は、船舶オブジェクト (Cruise) によって決定されます. シーンでは、パス ポイントがオブジェクトに設定され、オブジェクトの実行軌跡が大円弧予測子を使用して計算されます. 軌跡の実行時間は、CZML 出力全体の終了時間を決定します。 czml ファイルの後のセシウム. シミュレーション実行効果は直感的に見ることができます. クルーズが最後まで実行されると、シミュレーションはサイクルが最初から始まることを示しています.

上記のコードの 443 行を参照してください。したがって、衛星オブジェクト ERS1 のシミュレーション時間は 24h (計算時間) であると判断されます。

センサーについて

出力された czml ファイルには、センサーの説明に "agi_conicSensor" という属性があります. この属性は、(セシウム) 端末でセンサーを表示するために AGI によって特別にカスタマイズされています. インターネットで関連情報を確認したところ、表示をサポートする関連パッケージがあります。この方法では、多くの試みが行われましたが、成功せずに、センサー (スキャン、ポジショニング、追跡など) の効果が Web ブラウザー端末に表示されません。基本的な理由は、バージョンが一致していないこと、Cesium のバージョンの方が更新が高速であること、センサー ディスプレイをサポートする JS パッケージが 6 年以上更新されていないことです。

成功例あり:https://blog.csdn.net/Gua_guagua/article/details/125024376

配向性について

出力 czml ファイルには、シーン オブジェクトの方向属性を記述する多数のコードがあります。この属性は、主に、オブジェクトの 3D モデル表示の動的ポインティング (方向) を制限します。大規模なシーン デモンストレーションのみの場合は、データのこの部分は無視できます.これにより、czml ファイルのサイズを大幅に削減できます.

オブジェクトに関する 3D モデル ファイル

出力 czml ファイルでキーワード「gltf」または「glb」を検索します。このキーワードに関連する属性は、シーン内のオブジェクトの 3D 表示モデルを指定します。Cesium ターミナルでオブジェクトをダブルクリックすると、オブジェクトの視点に切り替わります。 3D モデルを表示 オブジェクトを表示します。STK のインストール ディレクトリを検索 (またはローカルにキャッシュされた Web ページ ファイルを検索) して、関連するモデル ファイルをローカルで見つけ、それらを独自の Web サービス ディレクトリに公開することで、AGI の公式 Web サイトにアクセスしなくても、オンラインでリアルタイムにファイルを取得できます。

クライアントセシウムディスプレイ

IIS Web サーバーのアドレスが 192.168.1.111 であるとします。

このシリーズの以前のブログ投稿に基づいて、次のコードを追加します。

      Sandcastle.addToolbarButtonWy("计算并加载CZML文件场景", function () {
        statusDisplay.innerHTML = "正在执行计算,请耐心等待……";
        $.ajax({
          type : "POST",
          contentType : "application/json; charset:utf-8",
          url : "http://192.168.1.111:8081/StkServ.asmx/CzmlExport",
          success : function (data) {
            // 注:直接返回的是ajax解析生成的JSON对象
            if(data["isSuccess"] == 0) {
              // 计算成功,加载结果czml文件
              viewer.dataSources.removeAll();
              viewer.dataSources.add(Cesium.CzmlDataSource.load(data["calResult"]));
              viewer.camera.flyHome(0);
              statusDisplay.innerHTML = "成功执行计算,结果CZML文件:" + data["calResult"];
            }
            else {
              statusDisplay.innerHTML = "计算失败,原因:" + data["description"];
            }
          },
          error : function(xhr) { // for test
            statusDisplay.innerHTML = xhr.responseText;
          }
        });
      });

最初の読み込みに失敗しました。サーバーのローカル ファイル ディレクトリを確認すると、czml ファイルが正常に出力されました。クライアントがサーバーの czml ファイルを読み込めないことが原因であると判断した後、サーバーに IIS の MIME タイプを手動で追加する必要があります。つまり、タイプ「application/czml」、「.czml」のファイルを追加します'。

IIS マネージャーで MIME タイプを選択します。

「MIME Type」をクリックしたら、右側の「Add」をクリック。

ポップアップ ウィンドウに次のような出力が表示されるので、[OK] ボタンをクリックして保存します。

セシウム表示インターフェース:

おすすめ

転載: blog.csdn.net/wangyulj/article/details/129005263