/// <summary> /// Perform rendering activities to produce a bitmap tile /// </summary> public RequestErrorStatus PerformRender(DisplayMode mode, IPipelineProcessor processor, IPlanViewPalette colourPalette, IFilterSet filters, ILiftParameters liftParams) { // Obtain the display responsible for rendering the thematic information for this mode Displayer = PVMDisplayerFactory.GetDisplayer(mode /*, FICOptions*/); if (Displayer == null) { processor.Response.ResultStatus = RequestErrorStatus.UnsupportedDisplayType; return(processor.Response.ResultStatus); } // Create and assign the colour palette logic for this mode to the displayer if (colourPalette == null) { if (mode == DisplayMode.CCA || mode == DisplayMode.CCASummary) { Displayer.SetPalette(Utilities.ComputeCCAPalette(processor.SiteModel, filters.Filters[0].AttributeFilter, mode)); if (Displayer.GetPalette() == null) { processor.Response.ResultStatus = RequestErrorStatus.FailedToGetCCAMinimumPassesValue; return(processor.Response.ResultStatus); } } else { Displayer.SetPalette(PVMPaletteFactory.GetPalette(processor.SiteModel, mode, processor.SpatialExtents)); } } else { Displayer.SetPalette(colourPalette); } // Create the world coordinate display surface the displayer will render onto Displayer.MapView = new MapSurface { SquareAspect = IsWhollyInTermsOfGridProjection }; var view = Displayer.MapView; // Set the world coordinate bounds of the display surface to be rendered on view.SetBounds(NPixelsX, NPixelsY); if (IsWhollyInTermsOfGridProjection) { view.FitAndSetWorldBounds(OriginX, OriginY, OriginX + Width, OriginY + Height, 0); } else { view.SetWorldBounds(OriginX, OriginY, OriginX + Width, OriginY + Height, 0); } // Provide data smoothing support to the displayer for the rendering operation being performed ((IProductionPVMConsistentDisplayer)Displayer).DataSmoother = DIContext.Obtain <Func <DisplayMode, IDataSmoother> >()(mode); // Set the rotation of the displayer rendering surface to match the tile rotation due to the project calibration rotation view.SetRotation(TileRotation); ConstructPVMTaskAccumulator(processor); // Displayer.ICOptions = ICOptions; // Set the skip-step area control cell selection parameters for this tile render. Note that the floating point // skip step algorithm is requested, and a user origin is configured that offsets the sampling grid by half a pixel // size to matching the skip-stepping the PVM accumulator will use when transcribing cell data from sub grids into // the accumulator. Note that the area control set is not configured with a rotation - this is taken into account // through the mapview rotation configured above processor.Pipeline.AreaControlSet = new AreaControlSet(false, view.XPixelSize, view.YPixelSize, view.XPixelSize / 2.0, view.YPixelSize / 2.0, 0.0); processor.Pipeline.LiftParams = liftParams; // todo PipeLine.NoChangeVolumeTolerance = FICOptions.NoChangeVolumeTolerance; // Perform the sub grid query and processing to render the tile var pipelineProcessorStopWatch = Stopwatch.StartNew(); processor.Process(); _log.LogInformation($"Pipeline processor completed in {pipelineProcessorStopWatch.Elapsed}"); if (processor.Response.ResultStatus == RequestErrorStatus.OK) { // Render the collection of data in the aggregator var consistentRenderStopWatch = Stopwatch.StartNew(); (Displayer as IProductionPVMConsistentDisplayer)?.PerformConsistentRender(); _log.LogInformation($"Consistent render complated in {consistentRenderStopWatch.Elapsed}"); PerformAnyRequiredDebugLevelDisplay(); if (DebugDrawDiagonalCrossOnRenderedTilesDefault) { // Draw diagonal cross and top left corner indicators view.DrawLine(view.OriginX, view.OriginY, view.LimitX, view.LimitY, Color.Red); view.DrawLine(view.OriginX, view.LimitY, view.LimitX, view.OriginY, Color.Red); // Draw the horizontal line a little below the world coordinate 'top' of the tile to encourage the line // drawing algorithm not to clip it view.DrawLine(view.OriginX, view.LimitY, view.OriginX, view.CenterY, Color.Red); view.DrawLine(view.OriginX, view.LimitY - 0.01, view.CenterX, view.LimitY - 0.01, Color.Red); } } return(processor.Response.ResultStatus); }