STK + C# + Cesium joint programming (2): CZML file generation and loading

overview

This article is a continuation of the previous blog post. In the previous article, the related technologies of C# .NET Framework (Web Service) + STK + Cesium front-end display were verified. This article demonstrates how to create STK through the Pro Tutorial instance and the Export CZML plug-in attached to the STK installation. Scene, create objects, calculate Access, output CZML files through plug-ins, and load and display scenes on the client side.

CZML is a specification for describing temporal dynamic graphics scenes in JSON format. Mainly used for display in the Cesium client browser, CZML can describe lines, points, billboards, models, and other graphics primitives and specify how they change over time. By extending resources with CZML, richer scene effects can be achieved, such as displaying the detection dynamics of sensors (Sensors) in STK scenes.

mission target

In this example, the STK scene is generated on the server side by referring to the sample code given by STKPro Stutorial, and the czml format file (stored locally on the server) is output through the STK Export CZML plug-in, and the client browser realizes the reproduction of the scene by loading the czml file.

Environment and version

  • STK 11.6

  • VS2017(C#, .NETFramework 4.8)

  • Cesium-1.99

related resources

See the previous blog post in this series: https://blog.csdn.net/wangyulj/article/details/128914391

Implementation process

Server-side scene generation

The code is as follows (notes are added based on the STK sample code):

        [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);
        }

The list of other related methods in the code is as follows:

Unified initialization management of the STK process (InvokeSTK method)

        // 获取或创建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;
        }

Other methods:

       // 释放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;
        }

Code description:

The variables in the code are global variables of the m_STKApp and m_STKRoot classes, defined as follows:

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

STKProTutorial instance creation scene process

  • Obtain or create an STK application (process) instance;

  • Set the unit (it is recommended to set each calculation unit according to the actual situation before each initialization scene);

  • Set the simulation time;

  • Create ground facilities (Facility) through the Children.New() method;

  • Create ground facilities from local database files installed by STK;

  • Create a target (Target) object, the target (Iceberg) to be searched in the scene;

  • Create a Ship object and use the large arc predictor ( ePropagatorGreatArc ) to calculate the ship's trajectory.

  • Creating a Satellite (TDRS), demonstrates how to use a two-body (motion) predictor ( ePropagatorTwoBody ) to calculate a satellite's orbit.

  • Load and create satellites (TDRS_3) from the STK database file, and use the SGP4 orbit predictor to calculate the satellite orbit (the sgp4.Propagate() method is not actually executed in the code, but the output still has the orbit/trajectory of the satellite, because it is from the existing database file. Is it loaded? Or is orbital calculation performed by default?).

  • Create a satellite (ERS1), which is the main satellite in the scene to demonstrate area search, using the J4 perturbation (second order) predictor for orbit prediction (calculation).

  • Create a space station (Shuttle), which is actually a satellite object (eSatellite), use the J4 predictor to calculate the orbit, and set a complex outline for the two-dimensional display of the space station. The effect can be seen in the STK interface, and the output CZML file There is no relevant display data in .

  • Create an area target (AreaTarget) representing the search area, and define the search area through the ePattern pattern.

  • Perform an Access calculation from satellite ERS1 to the search area.

  • Add two sensors to satellite ERS1, one for uplink (fixed pointing) and one for downlink (tracking mode).

  • Adds a sensor (fixed pointing) to ground station Wallops.

  • Recalculate the orbit of ERS1, the calculation period is 24h, and customize the display characteristics of different time periods.

  • Computation of Access data from sensor Horizon (of satellite ERS1) to ground facility Baikonur.

Finally, execute the Command command to output the CZML file, the code is as follows (the above code lines 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);
      //-----------------------------------------------------------------

After testing, the last parameter of the 'ExportCZML' command must be specified, which is the address of the default 3D model. After the czml file is generated, the default source can be replaced according to the actual configuration of the application.

The generated czml file is about 2.6M in size.

About the resulting CZML file

Regarding the introduction of CZML files, there are many network resources, which can be searched by yourself. This article only lists a CSDN blog post for reference.

The use of CZML for Cesium learning: https://blog.csdn.net/Gua_guagua/article/details/125024376

simulation time

The simulation time specified in the code is 4 hours, the code is as follows: (Note: including the SetSimuTimes method)

            // 设置仿真时间: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;
        }

The simulation time of the actual output of the CZML file is more than 4 days, see the global settings of the first JSON element output by the czml file.

  {
    "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"
    }
  },
……

According to the code analysis, the simulation time of the output CZML file is based on the maximum simulation time output of each object in the scene. The simulation time in this example is determined by the Ship object (Cruise). In the scene, the path point is set for the object, and the running trajectory of the object is calculated by using the large arc predictor. The running time of the trajectory determines the end time of the entire CZML output, which can be loaded from Cesium after the czml file. The simulation running effect can be seen intuitively. When Cruise runs to the end, the simulation shows that the cycle starts from the beginning.

See line 443 of the above code, the simulation time of the satellite object ERS1 is thus determined to be 24h (calculation time).

About Sensors

In the output czml file, there is an attribute "agi_conicSensor" in the description of the sensor. This attribute is specially customized by AGI for the display of the sensor on the (Cesium) terminal. I checked the relevant information on the Internet, and there are related packages to support the display. In this practice, many attempts have been made, but without success, the sensor's (scanning, positioning, tracking, etc.) effects cannot be displayed on the Web browser terminal. The basic reason is that the version does not match, the Cesium version is iteratively updated faster, and the JS package to support the sensor display has not been updated for more than six years.

There are successful examples: https://blog.csdn.net/Gua_guagua/article/details/125024376

About the orientation attribute

In the output czml file, there are a large number of codes describing the orientation attribute of the scene object. This attribute mainly constrains the dynamic pointing (direction) of the object's 3D model display. If it is only a large-grained scene demonstration, this part of the data can be ignored. This can greatly reduce the size of the czml file.

3D model files about objects

Search for the keyword 'gltf' or 'glb' in the output czml file. The attributes related to this keyword specify the 3D display model of the object in the scene. Double-clicking the object in the Cesium terminal will switch to the object's viewpoint and display the 3D model Display the object. Search the STK installation directory (or search the locally cached webpage files) to find relevant model files locally. By publishing them in your own web service directory, you can obtain the files online in real time without visiting the official website of AGI.

Client Cesium display

Assume the IIS web server address is 192.168.1.111

Based on the previous blog post in this series, add the following code.

      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;
          }
        });
      });

The first loading failed, check the local file directory of the server, the czml file has been successfully output. After judging that the reason is that the client cannot load the czml file of the server, it is necessary to manually add the MIME type of IIS on the server, that is, add a file of type 'application/czml', '.czml'.

Select the MIME type in IIS Manager.

After clicking 'MIME Type', click 'Add' on the right.

In the pop-up window, the output is as follows, click the 'OK' button to save.

Cesium display interface:

Guess you like

Origin blog.csdn.net/wangyulj/article/details/129005263