예제 #1
0
        private void button10_Click(object sender, EventArgs e)
        {
            // Calculate Header Info
            LLBoundingBox bb = new LLBoundingBox(173, -44, 174, -43, false);
            //  Double Alt = 0;

            var v1 = MapUtil.LatLonToEcef(bb.South, bb.West, 0);

            listBox1.Items.Add($"WS Meters:{v1.X} , {v1.Y}");

            var v2 = MapUtil.LatLonToEcef(bb.North, bb.East, 0);

            listBox1.Items.Add($"EN Meters:{v2.X} , {v2.Y}");

            var v3 = MapUtil.LatLonToEcef(-43.5, 173.5, 0);

            listBox1.Items.Add($"EN Meters:{v3.X} , {v3.Y}");

            //var midpt = MapUtil.MidPointLL(new MapPoint(bb.West, bb.South), new MapPoint(bb.East, bb.North));
            // listBox1.Items.Add($"Midpoint:{MapUtil.Rad2Deg(midpt.Longitude)} , {MapUtil.Rad2Deg(midpt.Latitude)}");

            //var v4 = MapUtil.LatLonToEcef(MapUtil.Rad2Deg(midpt.Latitude), MapUtil.Rad2Deg(midpt.Longitude), 0);

            //listBox1.Items.Add($"Midpoint Meters:{v4.X} , {v4.Y}");
        }
예제 #2
0
        public async override Task <ElevationData> GetDemLL(double minLon, double minLat, double maxLon, double maxLat)

        {
            var rect = new LLBoundingBox(new MapPoint(minLon, minLat), new MapPoint(maxLon, maxLat));

            return(MakeTileDEM(rect));
        }
예제 #3
0
        private void btnDistance_Click(object sender, EventArgs e)
        {
            // Winner is  MapUtil.GetDistance for pole to pole
            listBox1.Items.Add("");
            var bb = new LLBoundingBox(0, 0, 0, 0, false);

            bb.West = -180.0; bb.East = -179.0; bb.South = 0.0; bb.North = 0.0;
            var d1 = MapUtil.GetDistance(bb.West, bb.South, bb.East, bb.North);

            listBox1.Items.Add($"Distance1:{d1}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            Char myChar = 'K';
            var  d2     = MapUtil.Distance3(bb.West, bb.South, bb.East, bb.South, myChar);

            listBox1.Items.Add($"Distance2:{d2}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            var d3 = MapUtil.DistanceTo(bb.West, bb.South, bb.East, bb.South, myChar);

            listBox1.Items.Add($"Distance3:{d3}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");

            bb.West = -180.0; bb.East = -179.0; bb.South = -45.0; bb.North = -45.0;
            d1      = MapUtil.GetDistance(bb.West, bb.South, bb.East, bb.North);
            listBox1.Items.Add($"Distance1:{Math.Round(d1,6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d2 = MapUtil.Distance3(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance2:{Math.Round(d2,6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d3 = MapUtil.DistanceTo(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance3:{Math.Round(d3,6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");

            bb.West = 0.0; bb.East = 1.0; bb.South = 0.0; bb.North = 0.0;
            d1      = MapUtil.GetDistance(bb.West, bb.South, bb.East, bb.North);
            listBox1.Items.Add($"Distance1:{Math.Round(d1, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d2 = MapUtil.Distance3(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance2:{Math.Round(d2, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d3 = MapUtil.DistanceTo(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance3:{Math.Round(d3, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");

            bb.West = -179.0; bb.East = 170.0; bb.South = 0.0; bb.North = 0.0;
            d1      = MapUtil.GetDistance(bb.West, bb.South, bb.East, bb.North);
            listBox1.Items.Add($"Distance1:{Math.Round(d1, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d2 = MapUtil.Distance3(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance2:{Math.Round(d2, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d3 = MapUtil.DistanceTo(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance3:{Math.Round(d3, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");

            bb.West = -90.0; bb.East = 90.0; bb.South = 0.0; bb.North = 0.0;
            d1      = MapUtil.GetDistance(bb.West, bb.South, bb.East, bb.North);
            listBox1.Items.Add($"Distance1:{Math.Round(d1, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d2 = MapUtil.Distance3(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance2:{Math.Round(d2, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d3 = MapUtil.DistanceTo(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance3:{Math.Round(d3, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");

            bb.West = 1.0; bb.East = 1.1; bb.South = 0.0; bb.North = 1.0;
            d1      = MapUtil.GetDistance(bb.West, bb.South, bb.East, bb.North);
            listBox1.Items.Add($"Distance1:{Math.Round(d1, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d2 = MapUtil.Distance3(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance2:{Math.Round(d2, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
            d3 = MapUtil.DistanceTo(bb.West, bb.South, bb.East, bb.South, myChar);
            listBox1.Items.Add($"Distance3:{Math.Round(d3, 6)}, (W,S - E,N) ,({bb.West} , {bb.South}) - ({bb.East} , {bb.North})");
        }
예제 #4
0
        public void MakeDemoTile(LLBoundingBox boundary)
        {
            MaximumHeight = float.NegativeInfinity;
            MinimumHeight = float.PositiveInfinity;
            if (GridSize != QMConstants.DemoResolutionGridSize)
            {
                GridSize = QMConstants.DemoResolutionGridSize;
                Array.Resize(ref ElevGrid, GridSize * GridSize);
                Array.Resize(ref EcefPoints, GridSize * GridSize);
            }

            var step = 20.0F / (GridSize - 1);

            var    XStep = (boundary.East - boundary.West) / (GridSize - 1);
            var    YStep = (boundary.North - boundary.South) / (GridSize - 1);
            float  hgt;
            int    pos = 0;
            double XPos;
            double YPos = boundary.South;

            for (int y = 0; y < GridSize; y++)
            {
                hgt  = QMConstants.DemoBaseHgt;
                XPos = boundary.West;
                for (int x = 0; x < GridSize; x++)
                {
                    // height
                    ElevGrid[pos] = hgt;

                    if (hgt < MinimumHeight)
                    {
                        MinimumHeight = hgt;
                    }
                    if (hgt > MaximumHeight)
                    {
                        MaximumHeight = hgt;
                    }

                    hgt = hgt + step;

                    // ECEF
                    EcefPoints[pos] = CoordinateUtils.geo_to_ecef(new Vector3()
                    {
                        X = MapUtils.Deg2Rad(XPos), Y = MapUtils.Deg2Rad(YPos), Z = hgt
                    });
                    XPos = XPos + XStep;
                    pos++;
                }

                YPos = YPos + YStep; // increase y
            }

            HasData = true;
            East    = boundary.East;
            West    = boundary.West;
            North   = boundary.North;
            South   = boundary.South;
        }
예제 #5
0
        private void btnCenter_Click(object sender, EventArgs e)
        {
            LLBoundingBox bb = new LLBoundingBox(170, -43, 180, -44, false);
            var           t1 = bb.GetCenter();

            listBox1.Items.Add($"BB Center Test1 Not Radians {t1.Longitude} , {t1.Latitude}");
            LLBoundingBox bb2 = new LLBoundingBox(MapUtil.Deg2Rad(170), MapUtil.Deg2Rad(-43), MapUtil.Deg2Rad(180), MapUtil.Deg2Rad(-44));
            var           t2  = bb2.GetCenter();

            listBox1.Items.Add($"BB Center Test2 Not Radians {MapUtil.Rad2Deg( t2.Longitude)} , {MapUtil.Rad2Deg(t2.Latitude)}");

            var t3 = MapUtil.MidPointRad(new MapPoint(MapUtil.Deg2Rad(170.0), MapUtil.Deg2Rad(-43)), new MapPoint(MapUtil.Deg2Rad(180.0), MapUtil.Deg2Rad(-44.0)));

            listBox1.Items.Add($"BB Center Test3 Not Radians {MapUtil.Rad2Deg(t3.Longitude)} , {MapUtil.Rad2Deg(t3.Latitude)}");
        }
예제 #6
0
        public void TileBuilder_BuildTile()
        {
            LLBoundingBox TileBoundaryLL = MapGeo.TileXYZToRectLL(0, 0, 20, out var yFlip);
            ElevationData elevData       = new ElevationData(0, 5);

            elevData.MakeEmptyTile(TileBoundaryLL, false);
            QMTileBuilder tileBuilder = new QMTileBuilder()
            {
                TileData = elevData,
                GridSize = elevData.GridSize
            };

            var res = tileBuilder.BuildQuantizedMeshTile();

            res.Should().Be(true);
            tileBuilder.QuantizedMeshTile.Should().HaveCountGreaterOrEqualTo(162);
            tileBuilder.QuantizedMeshTile.Should().HaveCountLessOrEqualTo(164);
        }
예제 #7
0
 public void MakeEmptyTile(LLBoundingBox boundary, bool hasLighting)
 {
     HasLighting = hasLighting;
     if (GridSize != QMConstants.FlatResolutionGridSize)
     {
         GridSize = QMConstants.FlatResolutionGridSize;
         Array.Resize(ref ElevGrid, GridSize * GridSize);
         Array.Resize(ref EcefPoints, GridSize * GridSize);
         if (hasLighting)
         {
             VertexNormals = new byte[GridSize * GridSize * 2];
             Triangles     = new Triangle[(GridSize - 1) * (GridSize - 1) * 2];
         }
     }
     Clear();
     HasData       = false;
     East          = boundary.East;
     West          = boundary.West;
     North         = boundary.North;
     South         = boundary.South;
     MaximumHeight = LowestElevation;
     MinimumHeight = LowestElevation;
     EcefPoints[0] = CoordinateUtils.geo_to_ecef(new Vector3()
     {
         X = MapUtils.Deg2Rad(East), Y = MapUtils.Deg2Rad(South), Z = LowestElevation
     });
     EcefPoints[1] = CoordinateUtils.geo_to_ecef(new Vector3()
     {
         X = MapUtils.Deg2Rad(West), Y = MapUtils.Deg2Rad(South), Z = LowestElevation
     });
     EcefPoints[2] = CoordinateUtils.geo_to_ecef(new Vector3()
     {
         X = MapUtils.Deg2Rad(East), Y = MapUtils.Deg2Rad(North), Z = LowestElevation
     });
     EcefPoints[3] = CoordinateUtils.geo_to_ecef(new Vector3()
     {
         X = MapUtils.Deg2Rad(West), Y = MapUtils.Deg2Rad(North), Z = LowestElevation
     });
 }
예제 #8
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="bbox"></param>
        /// <returns></returns>
        private ElevationData MakeTileDEM(LLBoundingBox bbox)
        {
            // Steps
            // Using bounding box get elevation data for tile
            // Calculate header info

            Vector3[]     ecefPoints;
            ElevationData ed = GetData(bbox, out ecefPoints);

            // Work out bounding sphere
            TileInfo tileInfo = new TileInfo();
            var      hdr      = tileInfo.CalculateHeaderInfo(ref ecefPoints, false);

            ed.CenterX = hdr.CenterX;
            ed.CenterY = hdr.CenterY;
            ed.CenterZ = hdr.CenterZ;
            ed.BoundingSphereCenterX = hdr.CenterX;
            ed.BoundingSphereCenterY = hdr.CenterY;
            ed.BoundingSphereCenterZ = hdr.CenterZ;
            ed.BoundingSphereRadius  = hdr.BoundingSphereRadius;

            // Work out HorizonOcclusionPoint
            var hop = HorizonOcclusionPoint.FromPoints(ecefPoints, tileInfo.BoundingSphere);

            ed.HorizonOcclusionPointX = hop.X;
            ed.HorizonOcclusionPointY = hop.Y;
            ed.HorizonOcclusionPointZ = hop.Z;

            /* Quicker cheat method untested
             * ed.HorizonOcclusionPointX = hdr.CenterX;
             * ed.HorizonOcclusionPointY = hdr.CenterY;
             * ed.HorizonOcclusionPointZ = maxElev;
             */

            // todo lighting

            return(ed);
        }
예제 #9
0
        private ElevationData GetData(LLBoundingBox bbox, out Vector3[] ecefPoints)
        {
            //todo get data from TRex
            //Boolean dataAvailable = true;
            // if ((lat >= -43.548006 & lat <= -43.547679) & (lon >= 172.632951 & lon <= 172.633542))
            ElevationData ed;

            LLBoundingBox data           = new LLBoundingBox(172.632951, -43.548006, 172.633542, -43.547679);
            bool          dataAvailable  = data.East >= bbox.West && data.West <= bbox.East && data.North >= bbox.South && data.South <= bbox.North;
            LLBoundingBox data2          = new LLBoundingBox(-0.124629, 51.500745, 1.0, 51.6);
            bool          dataAvailable2 = data2.East >= bbox.West && data2.West <= bbox.East && data2.North >= bbox.South && data2.South <= bbox.North;

            int _gridSize;

            if (dataAvailable | dataAvailable2)
            {
                _gridSize = GridSize;
            }
            else
            {
                _gridSize = 2;
            }
            ed         = new ElevationData(_gridSize);
            ecefPoints = new Vector3[_gridSize * _gridSize];

            int PixelCount = _gridSize - 1;

            var    yRange  = bbox.North - bbox.South;
            var    xRange  = bbox.East - bbox.West;
            var    xStep   = xRange / PixelCount;
            var    yStep   = yRange / PixelCount;
            float  minElev = float.PositiveInfinity;
            float  maxElev = float.NegativeInfinity;
            Random rnd     = new Random();
            int    i       = 0;
            float  hgt     = 0;
            var    HgtMode = 2;

            for (int y = 0; y < GridSize; y++)
            {
                for (int x = 0; x < GridSize; x++)
                {
                    var lat = bbox.South + (y * yStep);
                    var lon = bbox.West + (x * xStep);


                    if (HgtMode == 1)
                    {
                        ed.Elev[i] = rnd.Next(1, 8000);
                    }
                    else if (HgtMode == 2)
                    {
                        if ((lat >= -43.548006 & lat <= -43.547679) & (lon >= 172.632951 & lon <= 172.633542))
                        {
                            ed.Elev[i] = (float)10.0;
                        }
                        else if ((lat >= 51.500745 & lat <= 51.6) & (lon >= -0.124629 & lon <= 1.0))
                        {
                            ed.Elev[i] = rnd.Next(1, 10);
                        }
                        else
                        {
                            ed.Elev[i] = 0;
                        }
                    }

                    if (ed.Elev[i] < minElev)
                    {
                        minElev = ed.Elev[i];
                    }

                    if (ed.Elev[i] > maxElev)
                    {
                        maxElev = ed.Elev[i];
                    }

                    // Make ecef point list for later header calculations
                    ecefPoints[i] = Coord.geo_to_ecef(new Vector3()
                    {
                        X = MapUtil.Deg2Rad(lon), Y = MapUtil.Deg2Rad(lat), Z = ed.Elev[i]
                    });

                    i++;
                }
            }

            ed.MaximumHeight = maxElev;
            ed.MinimumHeight = minElev;
            return(ed);
        }
예제 #10
0
        /*
         * https://cesium.com/blog/2013/05/09/computing-the-horizon-occlusion-point/
         * private computeMagnitude(ellipsoid, position, scaledSpaceDirectionToPoint)
         * {
         * var scaledSpacePosition = ellipsoid.transformPositionToScaledSpace(position);
         * var magnitudeSquared = scaledSpacePosition.magnitudeSquared();
         * var magnitude = Math.sqrt(magnitudeSquared);
         * var direction = scaledSpacePosition.divideByScalar(magnitude);
         *
         * // For the purpose of this computation, points below the ellipsoid
         * // are considered to be on it instead.
         * magnitudeSquared = Math.max(1.0, magnitudeSquared);
         * magnitude = Math.max(1.0, magnitude);
         *
         * var cosAlpha = direction.dot(scaledSpaceDirectionToPoint);
         * var sinAlpha = direction.cross(scaledSpaceDirectionToPoint).magnitude();
         * var cosBeta = 1.0 / magnitude;
         * var sinBeta = Math.sqrt(magnitudeSquared - 1.0) * cosBeta;
         *
         * return 1.0 / (cosAlpha * cosBeta - sinAlpha * sinBeta);
         * }
         */

        /// <summary>
        /// By LatLon
        /// </summary>
        /// <param name="bb"></param>
        /// <returns></returns>
        private ElevationData MakeTileDEM(LLBoundingBox bb)
        {
            // todo we also need to comput header info for the quantized mesh


            Vector2 v;

            v.X = 0;
            v.Y = 0;
            int x2         = 0;
            int y2         = 0;
            int PixelCount = GridSize - 1;


            var DoRandom = false;
            int HgtMode  = 2;

            float minElev = float.PositiveInfinity;
            float maxElev = float.NegativeInfinity;

            Random rnd = new Random();

            ElevationData ed = new ElevationData(GridSize);

            var midPt = bb.GetCenter();
            //  var pt2 =  Coord.geo_to_ecef(new Vector3( MapUtil.Deg2Rad(midPt.Longitude), MapUtil.Deg2Rad(midPt.Latitude),0)); // zero elevation for now
            var pt = MapUtil.LatLonToEcef(midPt.Latitude, midPt.Longitude, 0); // zero elevation for now

            Vector3[] ecefPoints = new Vector3[GridSize * GridSize];

            try
            {
                // we are going to walk up from sw to ne for returning dem in latlon coordinates
                var yRange = bb.North - bb.South;
                var xRange = bb.East - bb.West;
                var xStep  = xRange / PixelCount;
                var yStep  = yRange / PixelCount;


                int   i   = 0;
                float hgt = 0;
                for (int y = 0; y < GridSize; y++)
                {
                    for (int x = 0; x < GridSize; x++)
                    {
                        var lat = bb.South + (y * yStep);
                        var lon = bb.West + (x * xStep);
                        v = MapProject(lat, lon); // MapProject is lat long


                        if (v.X >= Width)
                        {
                            v.X = Width - 1;
                        }
                        if (v.Y >= Depth)
                        {
                            v.Y = Depth - 1;
                        }
                        if (v.X < 0)
                        {
                            v.X = 0;
                        }
                        if (v.Y < 0)
                        {
                            v.Y = 0;
                        }

                        x2 = (int)v.X;
                        y2 = (int)v.Y;

                        //hgt = 0;
                        // if (i == 4)
                        //  hgt = 100;

                        if (HgtMode == 1)
                        {
                            ed.Elev[i] = rnd.Next(1, 8000);
                        }
                        else if (HgtMode == 2)
                        {
                            ed.Elev[i] = 0;
                            if (lat >= -43.548006 & lat <= -43.547679)
                            {
                                if (lon >= 172.632951 & lon <= 172.633542)
                                {
                                    ed.Elev[i] = (float)10.0;
                                }
                            }
                        }
                        else
                        {
                            hgt        = Map.GetPixel(x2, y2).GetBrightness(); // 0=black, 1= white
                            ed.Elev[i] = MapUtil.Lerp(0, 1, ElevMin, ElevMax, hgt);
                        }

                        if (ed.Elev[i] < minElev)
                        {
                            minElev = ed.Elev[i];
                        }

                        if (ed.Elev[i] > maxElev)
                        {
                            maxElev = ed.Elev[i];
                        }

                        // Make ecef point list for later calculations
                        ecefPoints[i] = Coord.geo_to_ecef(new Vector3()
                        {
                            X = MapUtil.Deg2Rad(lon), Y = MapUtil.Deg2Rad(lat), Z = ed.Elev[i]
                        });


                        i++;
                    }
                }
            }
            catch (Exception ex)
            {
#if DEBUG
                System.Diagnostics.Debug.WriteLine($"**** MakeTileDEM Exception ****:{ex} v:{v} x2{x2} y2{y2} ");
// file writer        System.Diagnostics.Trace.WriteLine($"**** MakeTileDEM Exception *********:{ex} v:{v} x2{x2} y2{y2} ");
#endif
            }

            // todo now make a ecfc array to calculate header info
            TileInfo tileInfo = new TileInfo();
            var      hdr      = tileInfo.CalculateHeaderInfo(ref ecefPoints, false);
            ed.CenterX = hdr.CenterX;
            ed.CenterY = hdr.CenterY;
            ed.CenterZ = hdr.CenterZ;
            ed.BoundingSphereCenterX = hdr.CenterX;
            ed.BoundingSphereCenterY = hdr.CenterY;
            ed.BoundingSphereCenterZ = hdr.CenterZ;
            ed.BoundingSphereRadius  = hdr.BoundingSphereRadius;
            ed.MaximumHeight         = maxElev;
            ed.MinimumHeight         = minElev;


            var hop = HorizonOcclusionPoint.FromPoints(ecefPoints, tileInfo.BoundingSphere);
            ed.HorizonOcclusionPointX = hop.X;
            ed.HorizonOcclusionPointY = hop.Y;
            ed.HorizonOcclusionPointZ = hop.Z;


            /*
             * // FIXME: is there a better choice for a horizon occlusion point?
             * // Currently it's the center of tile elevated to bbox's max Z
             * header.horizon_occlusion = c;
             * header.horizon_occlusion.z = bbox.max.z;
             *
             *
             * ed.HorizonOcclusionPointX = hdr.CenterX;
             * ed.HorizonOcclusionPointY = hdr.CenterY;
             * ed.HorizonOcclusionPointZ = maxElev;
             */
            return(ed);
        }
예제 #11
0
        /// <summary>
        /// Executor that implements requesting and rendering grid information to create the grid rows
        /// </summary>
        /// <returns></returns>
        public async Task <bool> ExecuteAsync()
        {
            // Get the lat lon boundary from xyz tile request
            TileBoundaryLL = MapGeo.TileXYZToRectLL(TileX, TileY, TileZ, out var yFlip);
            _log.LogInformation($"#Tile#.({TileX},{TileY}) Execute Start.  DMode:{DisplayMode}, HasLighting:{HasLighting}, Zoom:{TileZ} FlipY:{yFlip}. TileBoundary:{TileBoundaryLL.ToDisplay()}, DataModel:{DataModelUid}");

            if (TileZ == 0) // Send back default root tile
            {
                MakeRootTile();
                return(true);
            }

            SiteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(DataModelUid);
            if (SiteModel == null)
            {
                ResultStatus = RequestErrorStatus.NoSuchDataModel;
                _log.LogError($"Tile.({TileX},{TileY}) Failed to obtain site model for {DataModelUid}");
                return(false);
            }

            var siteModelExtentWithSurveyedSurfaces = SiteModel.GetAdjustedDataModelSpatialExtents(null);

            _log.LogDebug($"Tile.({TileX},{TileY}) Site model extents are {siteModelExtentWithSurveyedSurfaces}. TileBoundary:{TileBoundaryLL.ToDisplay()}");
            if (!siteModelExtentWithSurveyedSurfaces.IsValidPlanExtent) // No data return empty tile
            {
                return(BuildEmptyTile());
            }

            // We will draw all missing data just below lowest elevation for site
            LowestElevation = (float)siteModelExtentWithSurveyedSurfaces.MinZ - 1F;

            Initialise();                                           // setup tile requirements

            if (TileGridSize == QMConstants.FlatResolutionGridSize) // Too far out to see detail so return empty tile
            {
                return(BuildEmptyTile());
            }

            if (DisplayMode == QMConstants.DisplayModeDemo) // development use only
            {
                return(BuildDemoTile());
            }

            try
            {
                var setupResult = await SetupPipelineTask(siteModelExtentWithSurveyedSurfaces, SiteModel.CellSize);

                if (!setupResult)
                {
                    if (ResultStatus != RequestErrorStatus.InvalidCoordinateRange)
                    {
                        _log.LogError($"Tile.({TileX},{TileY}) Unable to setup pipelinetask.");
                    }
                    return(BuildEmptyTile());
                }

                processor.Process();

                if (GriddedElevationsResponse.ResultStatus != RequestErrorStatus.OK)
                {
                    _log.LogError($"Tile.({TileX},{TileY}) Unable to obtain data for gridded data. GriddedElevationRequestResponse: {GriddedElevationsResponse.ResultStatus.ToString()}");
                    return(BuildEmptyTile());
                }

                ElevData.HasData = !float.IsPositiveInfinity(task.MinElevation); // check for data

                // Developer Debugging Only
                if (ElevData.HasData)
                {
                    OutputDebugTile("Raw");
                }

                if (!ElevData.HasData)
                {
                    return(BuildEmptyTile());
                }

                _log.LogInformation($"#Tile#.({TileX},{TileY}) Data successfully sampled. GridSize:{TileGridSize} Min:{task.MinElevation}, Max:{task.MaxElevation} FirstElev:{GriddedElevDataArray[0, 0].Elevation}, LastElev:{GriddedElevDataArray[TileGridSize - 1, TileGridSize - 1].Elevation}");

                ElevData.HasLighting = HasLighting;
                // Transform gridded data into a format the mesh builder can use
                ConvertGridToDEM(task.MinElevation, task.MaxElevation);

                // Build a quantized mesh from sampled elevations
                QMTileBuilder tileBuilder = new QMTileBuilder()
                {
                    TileData = ElevData, GridSize = TileGridSize
                };
                _log.LogInformation($"Tile.({TileX},{TileY}) BuildQuantizedMeshTile. GridSize:{TileGridSize} Min:{ElevData.MinimumHeight}, Max:{ElevData.MaximumHeight}");
                if (!tileBuilder.BuildQuantizedMeshTile())
                {
                    _log.LogError($"Tile.({TileX},{TileY}) BuildQuantizedMeshTile returned false with error code: {tileBuilder.BuildTileFaultCode}");
                    return(false);
                }

                QMTileResponse.data         = tileBuilder.QuantizedMeshTile; // Make tile from mesh
                ResultStatus                = RequestErrorStatus.OK;
                QMTileResponse.ResultStatus = ResultStatus;
                _log.LogDebug($"#Tile#.({TileX},{TileY}) Execute End. Returning production tile. CesiumY:{yFlip}, Zoom:{TileZ}, GridSize:{TileGridSize}");

                return(true);
            }
            catch (Exception ex)
            {
                _log.LogError(ex, $"#Tile#.({TileX},{TileY}). Exception building QuantizedMesh tile: ");
                return(false);
            }
        }