예제 #1
0
        /// <summary>
        /// Setup pipeline for tile request
        /// </summary>
        /// <param name="siteModelExtent">Site Model Extent</param>
        /// <param name="cellSize">Cell Size</param>
        /// <returns></returns>
        private async Task <bool> SetupPipelineTask(BoundingWorldExtent3D siteModelExtent, double cellSize)
        {
            var requestDescriptor = Guid.NewGuid();

            if (DisplayMode == QMConstants.DisplayModeStandard)
            {
                // Note coords are always supplied lat long
                if (SiteModel.CSIB() == string.Empty)
                {
                    ResultStatus = RequestErrorStatus.EmptyCoordinateSystem;
                    _log.LogError($"Failed to obtain site model coordinate system CSIB file for Project:{DataModelUid}");
                    return(false);
                }
            }

            LLHCoords = new[] { new XYZ(MapUtils.Deg2Rad(TileBoundaryLL.West), MapUtils.Deg2Rad(TileBoundaryLL.South), 0),
                                new XYZ(MapUtils.Deg2Rad(TileBoundaryLL.East), MapUtils.Deg2Rad(TileBoundaryLL.North), 0),
                                new XYZ(MapUtils.Deg2Rad(TileBoundaryLL.West), MapUtils.Deg2Rad(TileBoundaryLL.North), 0),
                                new XYZ(MapUtils.Deg2Rad(TileBoundaryLL.East), MapUtils.Deg2Rad(TileBoundaryLL.South), 0) };

            // This will change in Part3 once development is complete
            var strCSIB   = DisplayMode == QMConstants.DisplayModeStandard ? SiteModel.CSIB() : DIMENSIONS_2012_DC_CSIB;
            var NEECoords = DIContext.Obtain <ICoreXWrapper>().LLHToNEE(strCSIB, LLHCoords.ToCoreX_XYZ(), CoreX.Types.InputAs.Radians).ToTRex_XYZ();

            GridIntervalX = (NEECoords[1].X - NEECoords[0].X) / (TileGridSize - 1);
            GridIntervalY = (NEECoords[1].Y - NEECoords[0].Y) / (TileGridSize - 1);

            _log.LogDebug($"#Tile#.({TileX},{TileY}) TileInfo: Zoom:{TileZ}, TileSizeXY:{Math.Round(NEECoords[1].X - NEECoords[0].X, 3)}m x {Math.Round(NEECoords[2].Y - NEECoords[0].Y, 3)}m, GridInterval(m) X:{Math.Round(GridIntervalX, 3)}, Y:{Math.Round(GridIntervalY, 3)}, GridSize:{TileGridSize}");

            var WorldTileHeight = MathUtilities.Hypot(NEECoords[0].X - NEECoords[2].X, NEECoords[0].Y - NEECoords[2].Y);
            var WorldTileWidth  = MathUtilities.Hypot(NEECoords[0].X - NEECoords[3].X, NEECoords[0].Y - NEECoords[3].Y);

            double dx = NEECoords[2].X - NEECoords[0].X;

            CenterX = NEECoords[2].X + dx / 2;
            double dy = NEECoords[2].Y - NEECoords[0].Y;

            CenterY = NEECoords[0].Y + dy / 2;

            // Calculate the tile rotation as the mathematical angle turned from 0 (due east) to the vector defined by dy/dx
            TileRotation = Math.Atan2(dy, dx);

            // Convert TileRotation to represent the angular deviation rather than a bearing
            TileRotation = (Math.PI / 2) - TileRotation;

            SetRotation(TileRotation);

            _log.LogDebug($"QMTile render executing across tile: [Rotation:{ MathUtilities.RadiansToDegrees(TileRotation)}] " +
                          $" [BL:{NEECoords[0].X}, {NEECoords[0].Y}, TL:{NEECoords[2].X},{NEECoords[2].Y}, " +
                          $"TR:{NEECoords[1].X}, {NEECoords[1].Y}, BR:{NEECoords[3].X}, {NEECoords[3].Y}] " +
                          $"World Width, Height: {WorldTileWidth}, {WorldTileHeight}");

            RotatedTileBoundingExtents.SetInverted();
            foreach (var xyz in NEECoords)
            {
                RotatedTileBoundingExtents.Include(xyz.X, xyz.Y);
            }


            // Intersect the site model extents with the extents requested by the caller
            _log.LogDebug($"Tile.({TileX},{TileY}) Calculating intersection of bounding box and site model {DataModelUid}:{siteModelExtent}");
            var dataSelectionExtent = new BoundingWorldExtent3D(RotatedTileBoundingExtents);

            dataSelectionExtent.Intersect(siteModelExtent);
            if (!dataSelectionExtent.IsValidPlanExtent)
            {
                ResultStatus = RequestErrorStatus.InvalidCoordinateRange;
                _log.LogInformation($"Tile.({TileX},{TileY}) Site model extents {siteModelExtent}, do not intersect RotatedTileBoundingExtents {RotatedTileBoundingExtents}");
                return(false);
            }

            // Compute the override cell boundary to be used when processing cells in the sub grids
            // selected as a part of this pipeline
            // Increase cell boundary by one cell to allow for cells on the boundary that cross the boundary
            SubGridTree.CalculateIndexOfCellContainingPosition(dataSelectionExtent.MinX,
                                                               dataSelectionExtent.MinY, cellSize, SubGridTreeConsts.DefaultIndexOriginOffset,
                                                               out var CellExtents_MinX, out var CellExtents_MinY);
            SubGridTree.CalculateIndexOfCellContainingPosition(dataSelectionExtent.MaxX,
                                                               dataSelectionExtent.MaxY, cellSize, SubGridTreeConsts.DefaultIndexOriginOffset,
                                                               out var CellExtents_MaxX, out var CellExtents_MaxY);
            var CellExtents = new BoundingIntegerExtent2D(CellExtents_MinX, CellExtents_MinY, CellExtents_MaxX, CellExtents_MaxY);

            CellExtents.Expand(1);

            // Setup Task
            task      = DIContext.Obtain <Func <PipelineProcessorTaskStyle, ITRexTask> >()(PipelineProcessorTaskStyle.QuantizedMesh) as QuantizedMeshTask;
            processor = DIContext.Obtain <IPipelineProcessorFactory>().NewInstanceNoBuild <SubGridsRequestArgument>(requestDescriptor: requestDescriptor,
                                                                                                                    dataModelID: DataModelUid,
                                                                                                                    gridDataType: GridDataType.Height,
                                                                                                                    response: GriddedElevationsResponse,
                                                                                                                    filters: Filters,
                                                                                                                    cutFillDesign: new DesignOffset(),
                                                                                                                    task: task,
                                                                                                                    pipeline: DIContext.Obtain <Func <PipelineProcessorPipelineStyle, ISubGridPipelineBase> >()(PipelineProcessorPipelineStyle.DefaultProgressive),
                                                                                                                    requestAnalyser: DIContext.Obtain <IRequestAnalyser>(),
                                                                                                                    requireSurveyedSurfaceInformation: true, //Rendering.Utilities.DisplayModeRequireSurveyedSurfaceInformation(DisplayMode.Height) && Rendering.Utilities.FilterRequireSurveyedSurfaceInformation(Filters),
                                                                                                                    requestRequiresAccessToDesignFileExistenceMap: false,
                                                                                                                    overrideSpatialCellRestriction: CellExtents,
                                                                                                                    liftParams: LiftParams
                                                                                                                    );

            // Set the grid TRexTask parameters for progressive processing
            processor.Task.RequestDescriptor = requestDescriptor;
            processor.Task.TRexNodeID        = RequestingTRexNodeID;
            processor.Task.GridDataType      = GridDataType.Height;

            // Set the spatial extents of the tile boundary rotated into the north reference frame of the cell coordinate system to act as
            // a final restriction of the spatial extent used to govern data requests
            processor.OverrideSpatialExtents.Assign(RotatedTileBoundingExtents);

            // Setup new grid array for results
            GriddedElevDataArray = new GriddedElevDataRow[TileGridSize, TileGridSize];
            // build up a data sample grid from SW to NE
            for (int y = 0; y < TileGridSize; y++)
            {
                for (int x = 0; x < TileGridSize; x++)
                {
                    var x1 = NEECoords[0].X + (GridIntervalX * x);
                    var y1 = NEECoords[0].Y + (GridIntervalY * y);
                    if (Rotating)
                    {
                        Rotate_point(x1, y1, out x1, out y1);
                    }
                    GriddedElevDataArray[x, y].Easting   = x1;
                    GriddedElevDataArray[x, y].Northing  = y1;
                    GriddedElevDataArray[x, y].Elevation = CellPassConsts.NullHeight;
                }
            }

            _log.LogDebug($"Tile.({TileX},{TileY}) Boundary grid coords:{string.Concat(NEECoords)}");
            _log.LogDebug($"Tile.({TileX},{TileY}) First Easting:{GriddedElevDataArray[0, 0].Easting} Northing:{GriddedElevDataArray[0, 0].Northing}");
            _log.LogDebug($"Tile.({TileX},{TileY}) Last Easting:{GriddedElevDataArray[TileGridSize - 1, TileGridSize - 1].Easting} Northing:{GriddedElevDataArray[TileGridSize - 1, TileGridSize - 1].Northing}");

            // point to container for results
            task.GriddedElevDataArray = GriddedElevDataArray;
            task.GridIntervalX        = GridIntervalX;
            task.GridIntervalY        = GridIntervalY;
            task.GridSize             = TileGridSize;
            // Tile boundary
            task.TileMinX        = NEECoords[0].X;
            task.TileMinY        = NEECoords[0].Y;
            task.TileMaxX        = NEECoords[1].X;
            task.TileMaxY        = NEECoords[1].Y;
            task.LowestElevation = LowestElevation;

            Azimuth       = 0;
            StartNorthing = NEECoords[0].Y;
            StartEasting  = NEECoords[0].X;

            // Commented out for purposes of demo until relationship between TRex mediated skip/step selection and the quantised mesh tile vertex based selection are better understood
            //    processor.Pipeline.AreaControlSet =
            //     new AreaControlSet(false, GridIntervalX, GridIntervalY, StartEasting, StartNorthing, Azimuth);

            if (!processor.Build())
            {
                _log.LogError($"Tile.({TileX},{TileY}) Failed to build pipeline processor for request to model {DataModelUid}");
                return(false);
            }

            return(true);
        }