/// <summary> /// Creates a demo tile. Useful for development /// </summary> /// <returns></returns> private bool BuildDemoTile() { _log.LogDebug($"#Tile.({TileX},{TileY}) Returning demo tile. (X:{TileX}, Y:{TileX},{TileY}, Z:{TileZ}), GridSize{QMConstants.DemoResolutionGridSize}"); // Even empty tiles must have header info correctly calculated if (ElevData.GridSize == QMConstants.NoGridSize) { ElevData = new ElevationData(LowestElevation, QMConstants.DemoResolutionGridSize); // elevation grid } ElevData.MakeDemoTile(TileBoundaryLL); QMTileBuilder tileBuilder = new QMTileBuilder() { TileData = ElevData, GridSize = ElevData.GridSize }; if (!tileBuilder.BuildQuantizedMeshTile()) { _log.LogError($"Tile.({TileX},{TileY}) failed to build demo tile. Error code: {tileBuilder.BuildTileFaultCode}"); return(false); } QMTileResponse.ResultStatus = RequestErrorStatus.OK; QMTileResponse.data = tileBuilder.QuantizedMeshTile; // return QM tile in response ResultStatus = RequestErrorStatus.OK; return(true); }
/// <summary> /// No data so return an empty tile /// </summary> /// <returns></returns> private bool BuildEmptyTile() { _log.LogDebug($"#Tile#.({TileX},{TileY}) Execute End. Returning empty tile. Zoom:{TileZ}, GridSize{QMConstants.FlatResolutionGridSize}"); // Even empty tiles must have header info correctly calculated if (ElevData.GridSize == QMConstants.NoGridSize) { ElevData = new ElevationData(LowestElevation, QMConstants.FlatResolutionGridSize); // elevation grid } ElevData.MakeEmptyTile(TileBoundaryLL, HasLighting); if (ElevData.HasLighting) { ComputeNormalMap(); } QMTileBuilder tileBuilder = new QMTileBuilder() { TileData = ElevData, GridSize = ElevData.GridSize }; if (!tileBuilder.BuildQuantizedMeshTile()) { _log.LogError($"Tile.({TileX},{TileY}) failed to build empty tile. Error code: {tileBuilder.BuildTileFaultCode}"); return(false); } QMTileResponse.ResultStatus = RequestErrorStatus.OK; QMTileResponse.data = tileBuilder.QuantizedMeshTile; // return QM tile in response ResultStatus = RequestErrorStatus.OK; return(true); }
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); }
/// <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); } }