예제 #1
0
        /* 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...
        }
예제 #2
0
        /// <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);
        }