public async Task Test_RenderOverlayTile_SurveyedSurface_ElevationOnly_Rotated(int initialRotation, int maxRotation, int rotationIncrement, double rotateAboutX, double rotateAboutY, ushort imagePixelSize) { AddClusterComputeGridRouting(); AddDesignProfilerGridRouting(); // Render a surveyed surface area of 100x100 meters in a tile 150x150 meters with a single cell with // production data placed at the origin // A location on the bug36372.ttm surface - X=247500.0, Y=193350.0 const double LOCATION_X = 0.0; const double LOCATION_Y = 0.0; // Find the location of the cell in the site model for that location SubGridTree.CalculateIndexOfCellContainingPosition (LOCATION_X, LOCATION_Y, SubGridTreeConsts.DefaultCellSize, SubGridTreeConsts.DefaultIndexOriginOffset, out var cellX, out var cellY); // Create the site model containing a single cell and add the surveyed surface to it var siteModel = BuildModelForSingleCellTileRender(HEIGHT_INCREMENT_0_5, cellX, cellY); DITAGFileAndSubGridRequestsWithIgniteFixture.ConstructSurveyedSurfaceEncompassingExtent(ref siteModel, new BoundingWorldExtent3D(-100, -100, 200, 200), DateTime.UtcNow, new double[] { 100, 100, 105, 105 }); var palette = PVMPaletteFactory.GetPalette(siteModel, DisplayMode.Height, siteModel.SiteModelExtent); var rotationDegrees = initialRotation; while (rotationDegrees <= maxRotation) { // Rotate the 'top right'/rotatedPoint by x degrees/ Negate the rotation so the RotatePointAbout method match survey angle convention var rot = MathUtilities.DegreesToRadians(-rotationDegrees); GeometryHelper.RotatePointAbout(rot, 0, 0, out var rotatedBottomLeftPointX, out var rotatedBottomLeftPointY, rotateAboutX, rotateAboutY); GeometryHelper.RotatePointAbout(rot, 100, 100, out var rotatedTopRightPointX, out var rotatedTopRightPointY, rotateAboutX, rotateAboutY); GeometryHelper.RotatePointAbout(rot, 0, 100, out var rotatedTopLeftPointX, out var rotatedTopLeftPointY, rotateAboutX, rotateAboutY); GeometryHelper.RotatePointAbout(rot, 100, 0, out var rotatedBottomRightPointX, out var rotatedBottomRightPointY, rotateAboutX, rotateAboutY); var mockConvertCoordinates = new Mock <ICoreXWrapper>(); mockConvertCoordinates.Setup(x => x.LLHToNEE(It.IsAny <string>(), It.IsAny <CoreXModels.XYZ[]>(), It.IsAny <CoreX.Types.InputAs>())).Returns(new CoreXModels.XYZ[] { new CoreXModels.XYZ(rotatedBottomLeftPointX, rotatedBottomLeftPointY, 0.0), new CoreXModels.XYZ(rotatedTopRightPointX, rotatedTopRightPointY, 0.0), new CoreXModels.XYZ(rotatedTopLeftPointX, rotatedTopLeftPointY, 0.0), new CoreXModels.XYZ(rotatedBottomRightPointX, rotatedBottomRightPointY, 0.0) } ); DIBuilder.Continue().Add(x => x.AddSingleton(mockConvertCoordinates.Object)).Complete(); var render = new RenderOverlayTile(siteModel.ID, DisplayMode.Height, new XYZ(0, 0), new XYZ(100, 100), false, // Coords are LLH for rotated, grid otherwise - the mocked conversion above will return the true rotated grid coordinates imagePixelSize, //PixelsX imagePixelSize, // PixelsY new FilterSet(new CombinedFilter()), new DesignOffset(), palette, Color.Black, Guid.Empty, new LiftParameters(), VolumeComputationType.None); var result = await render.ExecuteAsync(); result.Should().NotBeNull(); var filename = $"RotatedOverlayTileWithSurveyedSurface({imagePixelSize} pixels, rotate about {rotateAboutX},{rotateAboutY} by {rotationDegrees} degrees).bmp"; var path = Path.Combine("TestData", "RenderedTiles", "SurveyedSurface", filename); var saveFileName = ""; // @$"c:\temp\{filename}"; CheckSimpleRenderTileResponse(result, saveFileName, ""); rotationDegrees += rotationIncrement; } }
public TileRenderResponse Invoke(TileRenderRequestArgument arg) { try { // Tile requests can be a significant resource commitment. Ensure TPaaS will be listening... PerformTPaaSRequestLivelinessCheck(arg); var requestStopWatch = Stopwatch.StartNew(); _log.LogInformation("In TileRenderRequestComputeFunc.Invoke()"); try { // Supply the TRex ID of the Ignite node currently running this code to permit processing contexts to send // sub grid results to it. arg.TRexNodeID = TRexNodeID.ThisNodeID(StorageMutability.Immutable); _log.LogInformation($"Assigned TRexNodeId from local node is {arg.TRexNodeID}"); var render = new RenderOverlayTile (arg.ProjectID, arg.Mode, new XYZ(arg.Extents.MinX, arg.Extents.MinY), new XYZ(arg.Extents.MaxX, arg.Extents.MaxY), arg.CoordsAreGrid, arg.PixelsX, arg.PixelsY, arg.Filters, arg.ReferenceDesign, arg.Palette, Color.Black, arg.TRexNodeID, arg.LiftParams, arg.VolumeType); _log.LogInformation("Executing render.ExecuteAsync()"); using var bmp = render.ExecuteAsync().WaitAndUnwrapException(); _log.LogInformation($"Render status = {render.ResultStatus}"); if (bmp == null) { _log.LogInformation("Null bitmap returned by executor"); return(new TileRenderResponse { TileBitmapData = null, ResultStatus = render.ResultStatus }); } using var image = SKImage.FromBitmap(bmp); using var data = image.Encode(SKEncodedImageFormat.Png, 100); using var stream = RecyclableMemoryStreamManagerHelper.Manager.GetStream(); data.SaveTo(stream); return(new TileRenderResponse { TileBitmapData = stream.ToArray(), ResultStatus = render.ResultStatus }); } finally { _log.LogInformation($"Exiting TileRenderRequestComputeFunc.Invoke() in {requestStopWatch.Elapsed}"); // Flag tile renders that take more than 20 seconds to render... if (requestStopWatch.Elapsed > _tileRequestTimeSpanWarnLimit) { _log.LogInformation($"Tile render request required more than {_tileRequestTimeSpanWarnLimit} to complete"); } } } catch (Exception e) { _log.LogError(e, "Exception occurred in TileRenderRequestComputeFunc.Invoke()"); return(new TileRenderResponse { ResultStatus = Types.RequestErrorStatus.Exception }); } }