/* TODO ColorPaletteClassType() * private TICDisplayPaletteBaseClass ColorPaletteClassType() * { * case FMode of * ...Height : Result = TICDisplayPalette_Height; * ...CCV : Result = TICDisplayPalette_CCV; * ...CCVPercent : Result = TICDisplayPalette_CCVPercent; * ...Latency : Result = TICDisplayPalette_RadioLatency; * ...PassCount : Result = TICDisplayPalette_PassCount; * ...PassCountSummary : Result = TICDisplayPalette_PassCountSummary; // Palettes are fixed three color palettes - display will use direct transitions * ...RMV : Result = TICDisplayPalette_RMV; * ...Frequency : Result = TICDisplayPalette_Frequency; * ...Amplitude : Result = TICDisplayPalette_Amplitude; * ...CutFill : Result = TICDisplayPalette_CutFill; * ...Moisture : Result = TICDisplayPalette_Moisture; * ...TemperatureSummary : Result = TICDisplayPaletteBase; //TICDisplayPalette_Temperature; * ...GPSMode : Result = TICDisplayPaletteBase; //TICDisplayPalette_GPSMode; * ...CCVSummary : Result = TICDisplayPaletteBase; //TICDisplayPalette_CCVSummary; * ...CCVPercentSummary : Result = TICDisplayPalette_CCVPercent; * ...CompactionCoverage : Result = TICDisplayPalette_CoverageOverlay; * ...VolumeCoverage : Result = TICDisplayPalette_VolumeOverlay; * ...MDP : Result = TICDisplayPalette_MDP; // ajr15167 * ...MDPSummary : Result = TICDisplayPaletteBase; * ...MDPPercent : Result = TICDisplayPalette_MDPPercent; * ...MDPPercentSummary : Result = TICDisplayPalette_MDPPercent; * ...MachineSpeed : Result = TICDisplayPalette_MachineSpeed; * ...CCVPercentChange : Result = TICDisplayPalette_CCVPercent; * ...TargetThicknessSummary : Result = TICDisplayPalette_VolumeOverlay; * ...TargetSpeedSummary : Result = TICDisplayPalette_SpeedSummary; * ...CCVChange : Result = TICDisplayPalette_CCVChange; * ...CCA : Result = TICDisplayPalette_CCA; * ...CCASummary : Result = TICDisplayPalette_CCASummary; * * else * SIGLogMessage.PublishNoODS(Self, Format('ColorPaletteClassType: Unknown display type: %d', [Ord(FMode)]), ...Assert); * Result = TICDisplayPaletteBase; * end; * end; */ /* TODO: ComputeCCAPalette * function ComputeCCAPalette :Boolean; * var * I, J, K :Integer; * ResponseVerb :...VerbBase; * ServerResult :TICServerRequestResult; * ResponseDataStream :TStream; * CCAMinimumPasses :...CCAMinPassesValue; * CCAColorScale :...CCAColorScale; * CCAPalette :TColorPalettes; * * begin * Result = False; * * ResponseVerb = nil; * try * if Length(FFilter1.Machines) > 0 then * FMachineID = FFilter1.Machines[0].ID // Must be set by caller * else * FMachineID = -1; // will fail call * if not Assigned(ASNodeImplInstance) or ASNodeImplInstance.ServiceStopped then * begin * SIGLogMessage.PublishNoODS(Self, Format('%s.Execute: Aborting request as service has been stopped', [Self.ClassName]), ...Warning); * Exit; * end; * * ASNodeImplInstance.PSLoadBalancer.LoadBalancedPSService.GetMachineCCAMinimumPassesValue(FDataModelID, FMachineID, FFilter1.StartTime, FFilter1.EndTime, FFilter1.LayerID, ResponseVerb); * if Assigned(ResponseVerb) then * with ResponseVerb as ...Verb_SendResponse do * begin * ServerResult = TICServerRequestResult(ResponseCode); * ResponseDataStream = ResponseData; * if (ServerResult = ...NoError) and assigned(ResponseData) then * begin * CCAMinimumPasses = ReadSmallIntFromStream(ResponseDataStream); * * Result = CCAMinimumPasses > 0; * * if not Result then * Exit; * * CCAColorScale = ...CCAColorScaleManager.CreateCoverageScale(CCAMinimumPasses); * try * SetLength(CCAPalette.Transitions, CCAColorScale.TotalColors); * * J = Low(CCAPalette.Transitions); * k = High(CCAPalette.Transitions); * for I = J to K do * begin * CCAPalette.Transitions[I].Color = CCAColorScale.ColorSegments[K - I].Color; * CCAPalette.Transitions[I].Value = I+1; * end; * CCAPalette.ConvertRGBToBGR; // gets done again but needed to match Anatoli palette test :) * WorkingColorPalette.PopulateFromPaletteColors(CCAPalette); * WorkingColorPalette.TransitionColors.ValuesCount = Length(CCAPalette.Transitions); * finally * if Assigned(CCAColorScale) then * FreeAndNil(CCAColorScale); * end; * end * else * SIGLogMessage.PublishNoODS(Self, Format('%s.Execute: GetMachineCCAMinimumPassesValue Failed for InternalSiteModelMachineIndex: %d. ReturnCode:%d', [Self.ClassName, FMachineID, Ord(ServerResult)]), ...Warning); * end; * finally * if Assigned(ResponseVerb) then * FreeAndNil(ResponseVerb); * end; * end; */ /* TODO: CreateAndInitialiseWorkingColorPalette * function CreateAndInitialiseWorkingColorPalette :Boolean; * begin * Result = True; * * // Create a scaled palette to use when rendering the data * try * if ColorPaletteClassType<> Nil then * begin * * WorkingColorPalette = ColorPaletteClassType.Create; * WorkingColorPalette.SmoothPalette = FMode = ...CutFill; * * // CCASummary is done per machine id * if FMode in [...CCA, ...CCASummary] * then * Result = ComputeCCAPalette * else * begin * if Length(FColorPalettes.Transitions) = 0 then * WorkingColorPalette.SetToDefaults * else * WorkingColorPalette.PopulateFromPaletteColors(FColorPalettes); * end; * * if Result then * WorkingColorPalette.ComputePalette; * end * else * WorkingColorPalette = Nil; * * Except * On e:Exception do * SIGLogMessage.PublishNoODS(Self, Format('%s.Execute: Error: %s ', [Self.ClassName, e.Message]), ...Exception); * end; * end; */ /// <summary> /// Renders all sub grids in a representational style that indicates where there is data, but nothing else. This is used for large scale displays /// (zoomed out a lot) where meaningful detail cannot be drawn on the tile /// </summary> private SKBitmap RenderTileAsRepresentationalDueToScale(ISubGridTreeBitMask overallExistenceMap) { using (var RepresentationalDisplay = PVMDisplayerFactory.GetDisplayer(Mode /*, FICOptions*/)) { using (var mapView = new MapSurface { SquareAspect = false }) { mapView.SetRotation(TileRotation); RepresentationalDisplay.MapView = mapView; RepresentationalDisplay.MapView.SetBounds(NPixelsX, NPixelsY); RepresentationalDisplay.MapView.SetWorldBounds(NEECoords[0].X, NEECoords[0].Y, NEECoords[0].X + WorldTileWidth, NEECoords[0].Y + WorldTileHeight, 0); // Iterate over all the bits in the sub grids drawing a rectangle for each one on the tile being rendered if (overallExistenceMap.ScanSubGrids(RotatedTileBoundingExtents, leaf => { leaf.CalculateWorldOrigin(out var WorldOriginX, out var WorldOriginY); (leaf as SubGridTreeLeafBitmapSubGrid)?.Bits.ForEachSetBit((x, y) => { RepresentationalDisplay.MapView.DrawRect(WorldOriginX + (x * overallExistenceMap.CellSize), WorldOriginY + (y * overallExistenceMap.CellSize), overallExistenceMap.CellSize, overallExistenceMap.CellSize, true, RepresentColor); }); return(true); })) { // Remove the canvas from the map view to prevent it's disposal (it's being returned to the caller) var canvas = RepresentationalDisplay.MapView.BitmapCanvas; RepresentationalDisplay.MapView.BitmapCanvas = null; return(canvas); } } } return(null); // It did not work out... }
/// <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); }