public void Test_ElevationSubGridRequests_RequestElevationSubGrids_NoSurveyedSurfaces_NoFilter() { var siteModel = Utilities.ConstructModelForTestsWithTwoExcavatorMachineTAGFiles(out var processedTasks); // Construct the set of requestors to query elevation sub grids needed for the summary volume calculations. var utilities = DIContext.Obtain <IRequestorUtilities>(); var Requestors = utilities.ConstructRequestors(null, siteModel, new OverrideParameters(), new LiftParameters(), utilities.ConstructRequestorIntermediaries(siteModel, new FilterSet(new CombinedFilter()), true, GridDataType.Height), AreaControlSet.CreateAreaControlSet(), siteModel.ExistenceMap); Requestors.Should().NotBeNull(); Requestors.Length.Should().Be(1); // Request all elevation sub grids from the model var requestedSubGrids = new List <IClientLeafSubGrid>(); siteModel.ExistenceMap.ScanAllSetBitsAsSubGridAddresses(x => { var requestSubGridInternalResult = Requestors[0].RequestSubGridInternal(x, true, false); if (requestSubGridInternalResult.requestResult == ServerRequestResult.NoError) { requestedSubGrids.Add(requestSubGridInternalResult.clientGrid); } }); requestedSubGrids.Count.Should().Be(4); (requestedSubGrids[0] as IClientHeightLeafSubGrid).Cells[0, 0].Should().Be(Consts.NullHeight); requestedSubGrids.Cast <IClientHeightLeafSubGrid>().Sum(x => x.CountNonNullCells()).Should().Be(427); }
/// <summary> /// Constructor for the sub grid retriever helper /// </summary> /// <param name="siteModel">The project this sub gris is being retrieved from</param> /// <param name="gridDataType">The type of client grid data sub grids to be returned by this retriever</param> /// <param name="storageProxy">The Ignite storage proxy to be used when requesting data from the persistent store</param> /// <param name="filter">The TRex spatial and attribute filtering description for the request</param> /// <param name="filterAnnex">An annex of data related to cell by cell filtering where the attributes related to that cell may change from cell to cell</param> /// <param name="hasOverrideSpatialCellRestriction">The spatially selected cells are masked by a rectangular restriction boundary</param> /// <param name="overrideSpatialCellRestriction"></param> /// <param name="prepareGridForCacheStorageIfNoSieving">The cell coordinate bounding box restricting cells involved in the request</param> /// <param name="maxNumberOfPassesToReturn">The maximum number of passes in a cell in a sub grid that will be considered when processing the request</param> /// <param name="areaControlSet">The skip/step area control set for selection of cells with sub grids for processing. Cells not identified by the control set will return null values.</param> /// <param name="populationControl">The delegate responsible for populating events depended on for processing the request.</param> /// <param name="pDExistenceMap">The production data existence map for the project the request relates to</param> /// <param name="overrides">The set of overriding machine event values to use</param> /// <param name="liftParams">The set of layer/lift analysis parameters to use</param> public ProgressiveVolumesSubGridRetriever(ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, bool prepareGridForCacheStorageIfNoSieving, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pDExistenceMap, IOverrideParameters overrides, ILiftParameters liftParams) : base(siteModel, gridDataType, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, prepareGridForCacheStorageIfNoSieving, maxNumberOfPassesToReturn, storageProxy, areaControlSet, populationControl, pDExistenceMap, overrides, liftParams) { // Clear any time element from the supplied filter. Time constraints ar derived from the startDate and endDate parameters filter.AttributeFilter.HasTimeFilter = false; // Clear any instruction in the filter to extract the earliest value - this has no meaning in progressive calculations filter.AttributeFilter.ReturnEarliestFilteredCellPass = false; // Remove any first/last/highest/lowest aspect from the filter - this has no meaning in progressive calculations filter.AttributeFilter.HasElevationTypeFilter = false; // Remove any machine filtering - the intent here is to examine volume progression over time, machine breakdowns don't make sense at this point filter.AttributeFilter.HasMachineFilter = false; }
/// <summary> /// Constructor /// </summary> public SubGridRequestsBase(ITRexTask tRexTask, Guid siteModelID, Guid requestID, Guid trexNodeId, GridDataType requestedGridDataType, bool includeSurveyedSurfaceInformation, ISubGridTreeBitMask prodDataMask, ISubGridTreeBitMask surveyedSurfaceOnlyMask, IFilterSet filters, DesignOffset referenceDesign, AreaControlSet areaControlSet, Action <TSubGridsRequestArgument> customArgumentInitializer, SubGridsRequestComputeStyle subGridsRequestComputeStyle) : this() { TRexTask = tRexTask; SiteModelID = siteModelID; RequestID = requestID; TRexNodeId = trexNodeId; RequestedGridDataType = requestedGridDataType; IncludeSurveyedSurfaceInformation = includeSurveyedSurfaceInformation; ProdDataMask = prodDataMask; SurveyedSurfaceOnlyMask = surveyedSurfaceOnlyMask; Filters = filters; ReferenceDesign = referenceDesign; AreaControlSet = areaControlSet; CustomArgumentInitializer = customArgumentInitializer; SubGridsRequestComputeStyle = SubGridsRequestComputeStyle; }
public void AreaControlSet_Integer_WorldOriginCenterCell00() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = siteModelCellsize * 2; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(true, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = siteModelCellsize / 2; double subGridWorldOriginY = siteModelCellsize / 2; var subGridMoniker = "theSubGridMoniker"; var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, subGridMoniker, areaControlSet, siteModelCellsize, out SubGridTreeBitmapSubGridBits sieveBitmask); Assert.True(sieveFilterInUse, "sieve filter should have been generated"); // 256/1024 set, first set at 0,0 Assert.True(sieveBitmask.CountBits() == 256, $"Incorrect count of bits set. Expected 256 but got {sieveBitmask.CountBits()}"); var rowXActual = sieveBitmask.RowToString(0); var rowXExpected = " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0"; Assert.True(rowXExpected == rowXActual, "bitSet for row 0 is invalid"); rowXActual = sieveBitmask.RowToString(2); Assert.True(rowXExpected == rowXActual, "bitSet for row 2 is invalid"); rowXActual = sieveBitmask.RowToString(1); rowXExpected = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; Assert.True(rowXExpected == rowXActual, "bitSet for row 1 is invalid"); rowXActual = sieveBitmask.RowToString(3); Assert.True(rowXExpected == rowXActual, "bitSet for row 3 is invalid"); }
private List <IClientLeafSubGrid> GetSubGrids(CoordType coordType, OutputTypes outputType, bool isRawDataAsDBaseRequired, out CSVExportRequestArgument requestArgument, out ISiteModel siteModel, string tagFileDirectory = "ElevationMappingMode-KettlewellDrive") { siteModel = SetupSiteAndRequestArgument(coordType, outputType, isRawDataAsDBaseRequired, tagFileDirectory, out requestArgument); var overrides = requestArgument.Overrides; var liftParams = requestArgument.LiftParams; var utilities = DIContext.Obtain <IRequestorUtilities>(); var gridDataType = outputType == OutputTypes.PassCountLastPass || outputType == OutputTypes.VedaFinalPass ? GridDataType.CellProfile : GridDataType.CellPasses; var requestors = utilities.ConstructRequestors(null, siteModel, requestArgument.Overrides, requestArgument.LiftParams, utilities.ConstructRequestorIntermediaries(siteModel, requestArgument.Filters, false, gridDataType), AreaControlSet.CreateAreaControlSet(), siteModel.ExistenceMap); requestors.Should().NotBeNull(); requestors.Length.Should().Be(1); // Request sub grids from the model var requestedSubGrids = new List <IClientLeafSubGrid>(); siteModel.ExistenceMap.ScanAllSetBitsAsSubGridAddresses(x => { var requestSubGridInternalResult = requestors[0].RequestSubGridInternal(x, true, false); if (requestSubGridInternalResult.requestResult == ServerRequestResult.NoError) { requestedSubGrids.Add(requestSubGridInternalResult.clientGrid); } }); requestedSubGrids.Count.Should().Be(tagFileDirectory == "ElevationMappingMode-KettlewellDrive" ? 18 : 9); return(requestedSubGrids); }
public void MasksOutValues_WithoutSurveyedSurfaces() { SetupTestIgniteRouting(); var(siteModel, filter) = CreateSiteModelWithSimpleDesign(); // Create a sub grid at the Northwest origin so that it covers the small TIN design surrounding the // [CellSize / 2, CellSize / 2] point var baseTime = DateTime.UtcNow; var cellPasses = new CellPass[32, 32][]; SubGridUtilities.SubGridDimensionalIterator((x, y) => { cellPasses[x, y] = Enumerable.Range(0, 1).Select(p => new CellPass { Height = 1.0f, InternalSiteModelMachineIndex = siteModel.Machines[0].InternalSiteModelMachineIndex, Time = baseTime.AddMinutes(p), PassType = PassType.Front }).ToArray(); }); DITAGFileAndSubGridRequestsFixture.AddSingleSubGridWithPasses(siteModel, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, cellPasses); // Construct a requestor and ask it to retrieve the sub grid from the site model, using the filter // with the surface design mask var utilities = DIContext.Obtain <IRequestorUtilities>(); var requestors = utilities.ConstructRequestors(null, siteModel, new OverrideParameters(), new LiftParameters(), utilities.ConstructRequestorIntermediaries(siteModel, new FilterSet(filter), false, GridDataType.Height), AreaControlSet.CreateAreaControlSet(), siteModel.ExistenceMap); requestors.Length.Should().Be(1); var response = requestors[0].RequestSubGridInternal (new SubGridCellAddress(SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset), true, false); response.requestResult.Should().Be(ServerRequestResult.NoError); response.clientGrid.Should().NotBeNull(); // Ensure the filtered cell has data response.clientGrid.FilterMap[0, 0].Should().BeTrue(); (response.clientGrid as IClientHeightLeafSubGrid).Cells[0, 0].Should().Be(1.0f); // Ensure no other cells have data response.clientGrid.FilterMap.CountBits().Should().Be(1); var subGrid = response.clientGrid as IClientHeightLeafSubGrid; var count = 0; subGrid.ForEach((x, y) => count += subGrid.Cells[x, y] == 1.0f ? 1 : 0); count.Should().Be(1); }
public void Test_AreaControlSet() { var argument = new AreaControlSet(true, 1000, 999, 10, 99, 8); var result = SimpleBinarizableInstanceTester.TestClassEx <AreaControlSet>(argument, "Custom AreaControlSet not same after round trip serialisation"); argument.PixelXWorldSize.Should().Be(result.member.PixelXWorldSize, "YPixelWorldSize are not equal"); }
private ISubGridRequestor[] CreateRequestorsForSingleCellTesting(ISiteModel siteModel, GridDataType gridDataType, ICombinedFilter[] filters) { // Construct the set of requestors to query elevation sub grids needed for the summary volume calculations. var utilities = DIContext.Obtain <IRequestorUtilities>(); var Requestors = utilities.ConstructRequestors(null, siteModel, new OverrideParameters(), new LiftParameters(), utilities.ConstructRequestorIntermediaries(siteModel, new FilterSet(filters), true, gridDataType), AreaControlSet.CreateAreaControlSet(), siteModel.ExistenceMap); Requestors.Should().NotBeNull(); Requestors.Length.Should().Be(1); return(Requestors); }
public void AreaControlSet_Float_PixelWorldSizeMustBeGreaterThan0() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = 0; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(false, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = 0; double subGridWorldOriginY = 0; var assignmentContext = new FilteredValueAssignmentContext(); var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, areaControlSet, siteModelCellsize, assignmentContext, out SubGridTreeBitmapSubGridBits _); Assert.False(sieveFilterInUse, "sieve filter should not have been generated for zero pixelWorldSize"); }
public void AreaControlSet_Integer_PixelWorldSizeMustBeGreaterThan0() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = 0; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(true, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = 0; double subGridWorldOriginY = 0; var subGridMoniker = "theSubGridMoniker"; var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, subGridMoniker, areaControlSet, siteModelCellsize, out SubGridTreeBitmapSubGridBits _); Assert.False(sieveFilterInUse, "sieve filter should not have been generated for zero pixelWorldSize"); }
/// <summary> /// Gets the production data values for the requested cell /// </summary> private async Task GetProductionData(ISiteModel siteModel, IDesignWrapper cutFillDesign, CellDatumResponse_ClusterCompute result, CellDatumRequestArgument_ClusterCompute arg) { var existenceMap = siteModel.ExistenceMap; var utilities = DIContext.Obtain <IRequestorUtilities>(); var requestors = utilities.ConstructRequestors(null, siteModel, arg.Overrides, arg.LiftParams, utilities.ConstructRequestorIntermediaries(siteModel, arg.Filters, true, GridDataType.CellProfile), AreaControlSet.CreateAreaControlSet(), existenceMap); // Get the sub grid relative cell location int cellX = arg.OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask; int cellY = arg.OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask; // Reach into the sub-grid request layer and retrieve an appropriate sub-grid var cellOverrideMask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); cellOverrideMask.SetBit(cellX, cellY); requestors[0].CellOverrideMask = cellOverrideMask; // using the cell address get the index of cell in clientGrid var thisSubGridOrigin = new SubGridCellAddress(arg.OTGCellX, arg.OTGCellY); var requestSubGridInternalResult = requestors[0].RequestSubGridInternal(thisSubGridOrigin, true, true); if (requestSubGridInternalResult.requestResult != ServerRequestResult.NoError) { if (requestSubGridInternalResult.requestResult == ServerRequestResult.SubGridNotFound) { result.ReturnCode = CellDatumReturnCode.NoValueFound; } else { Log.LogError($"Request for sub grid {thisSubGridOrigin} request failed with code {requestSubGridInternalResult.requestResult}"); } return; } var cell = ((ClientCellProfileLeafSubgrid)requestSubGridInternalResult.clientGrid).Cells[cellX, cellY]; if (cell.PassCount > 0) // Cell is not in our areaControlSet... { await ExtractRequiredValue(cutFillDesign, cell, result, arg); result.TimeStampUTC = cell.LastPassTime; } }
public void AreaControlSet_Integer_Unhappy_StepMustBeAtLeast2TimesCellSize() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; // pixelWorldSizeOrInterval/siteModelCellsize will result in stepSize = 1 double pixelWorldSizeOrIntervalXY = siteModelCellsize; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(true, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = 0; double subGridWorldOriginY = 0; var subGridMoniker = "theSubGridMoniker"; var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, subGridMoniker, areaControlSet, siteModelCellsize, out SubGridTreeBitmapSubGridBits _); Assert.False(sieveFilterInUse, "sieve filter should not have been generated where pixel size <2x siteModelCellSize"); }
public void AreaControlSet_Float_Unhappy_StepMustBeAtLeastCellSize() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; // pixelWorldSizeOrInterval/siteModelCellsize will result in stepSize = 1 double pixelWorldSizeOrIntervalXY = siteModelCellsize / 2; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(false, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = 0; double subGridWorldOriginY = 0; var assignmentContext = new FilteredValueAssignmentContext(); var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, areaControlSet, siteModelCellsize, assignmentContext, out SubGridTreeBitmapSubGridBits _); Assert.False(sieveFilterInUse, "sieve filter should not have been generated where pixelWorldSize < siteModelCellSize"); }
/// <summary> /// Serializes content to the writer /// </summary> public override void InternalToBinary(IBinaryRawWriter writer) { base.InternalToBinary(writer); VersionSerializationHelper.EmitVersionByte(writer, VERSION_NUMBER); writer.WriteGuid(RequestID); writer.WriteInt((int)GridDataType); writer.WriteByteArray(ProdDataMaskBytes); writer.WriteByteArray(SurveyedSurfaceOnlyMaskBytes); writer.WriteBoolean(IncludeSurveyedSurfaceInformation); AreaControlSet.ToBinary(writer); writer.WriteInt((int)SubGridsRequestComputeStyle); }
public void SubGridForCaching_IgnoresFilterMask_WithPartialNonOverlappingOverrideMaskRetriction() { var siteModel = BuildModelForSubGridRequest(); var retriever = new SubGridRetriever(siteModel, GridDataType.Height, siteModel.PrimaryStorageProxy, new CombinedFilter(), new CellPassAttributeFilterProcessingAnnex(), true, // Has override mask BoundingIntegerExtent2D.Inverted(), true, // prepareGridForCacheStorageIfNoSieving 1000, AreaControlSet.CreateAreaControlSet(), new FilteredValuePopulationControl(), siteModel.ExistenceMap, new OverrideParameters(), new LiftParameters() ); var clientGrid = ClientLeafSubGridFactoryFactory.CreateClientSubGridFactory().GetSubGridEx (GridDataType.Height, SubGridTreeConsts.DefaultCellSize, SubGridTreeConsts.SubGridTreeLevels, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset); var overrideMask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); overrideMask[10, 10] = true; // This does not overlap the filter but should still return a result var result = retriever.RetrieveSubGrid(clientGrid, overrideMask, out var seiveFilterInUse, () => { clientGrid.FilterMap.Clear(); clientGrid.FilterMap[0, 0] = true; clientGrid.ProdDataMap.Fill(); return(ServerRequestResult.NoError); }); result.Should().Be(ServerRequestResult.NoError); seiveFilterInUse.Should().BeFalse(); clientGrid.FilterMap.CountBits().Should().Be(1); // Only asking for the one cell... clientGrid.CountNonNullCells().Should().Be(1024); // All cells should be returned }
protected SubGridRetrieverBase(ISiteModel siteModel, GridDataType gridDataType, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, bool prepareGridForCacheStorageIfNoSieving, int maxNumberOfPassesToReturn, IStorageProxy storageProxy, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pDExistenceMap, IOverrideParameters overrides, ILiftParameters liftParams) { _segmentIterator = null; _cellPassIterator = null; _siteModel = siteModel; _gridDataType = gridDataType; _filter = filter; _filterAnnex = filterAnnex; _hasOverrideSpatialCellRestriction = hasOverrideSpatialCellRestriction; _overrideSpatialCellRestriction = overrideSpatialCellRestriction; _prepareGridForCacheStorageIfNoSieving = prepareGridForCacheStorageIfNoSieving; _maxNumberOfPassesToReturn = maxNumberOfPassesToReturn; _storageProxy = storageProxy; _populationControl = populationControl; _areaControlSet = areaControlSet; _pdExistenceMap = pDExistenceMap; _overrides = overrides; _liftParams = liftParams; // Create and configure the assignment context which is used to contain a filtered pass and // its attendant machine events and target values prior to assignment to the client sub grid. _assignmentContext = new FilteredValueAssignmentContext { Overrides = overrides, LiftParams = liftParams }; _filter.AttributeFilter.SiteModel = siteModel; _canUseGlobalLatestCells = _filter.AttributeFilter.LastRecordedCellPassSatisfiesFilter; }
public void AreaControlSet_Integer_Unhappy_Rotation_IgnoredForInteger() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = siteModelCellsize * 2; double userOriginXY = 0; var rotation = 90; var areaControlSet = new AreaControlSet(true, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = siteModelCellsize / 2; double subGridWorldOriginY = siteModelCellsize / 2; var subGridMoniker = "theSubGridMoniker"; var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, subGridMoniker, areaControlSet, siteModelCellsize, out SubGridTreeBitmapSubGridBits sieveBitmask); Assert.True(sieveFilterInUse, "sieve filter should have been generated"); // 256/1024 set, first set at 0,0 Assert.True(sieveBitmask.CountBits() == 256, $"Incorrect count of bits set. Expected 256 but got {sieveBitmask.CountBits()}"); }
/// <summary> /// Constructor for the sub grid retriever helper /// </summary> /// <param name="siteModel">The project this sub gris is being retrieved from</param> /// <param name="gridDataType">The type of client grid data sub grids to be returned by this retriever</param> /// <param name="storageProxy">The Ignite storage proxy to be used when requesting data from the persistent store</param> /// <param name="filter">The TRex spatial and attribute filtering description for the request</param> /// <param name="filterAnnex">An annex of data related to cell by cell filtering where the attributes related to that cell may change from cell to cell</param> /// <param name="hasOverrideSpatialCellRestriction">The spatially selected cells are masked by a rectangular restriction boundary</param> /// <param name="overrideSpatialCellRestriction"></param> /// <param name="prepareGridForCacheStorageIfNoSieving">The cell coordinate bounding box restricting cells involved in the request</param> /// <param name="maxNumberOfPassesToReturn">The maximum number of passes in a cell in a sub grid that will be considered when processing the request</param> /// <param name="areaControlSet">The skip/step area control set for selection of cells with sub grids for processing. Cells not identified by the control set will return null values.</param> /// <param name="populationControl">The delegate responsible for populating events depended on for processing the request.</param> /// <param name="pDExistenceMap">The production data existence map for the project the request relates to</param> /// <param name="overrides">The set of overriding machine event values to use</param> /// <param name="liftParams">The set of layer/lift analysis parameters to use</param> public SubGridRetriever(ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, bool prepareGridForCacheStorageIfNoSieving, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pDExistenceMap, IOverrideParameters overrides, ILiftParameters liftParams) : base(siteModel, gridDataType, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, prepareGridForCacheStorageIfNoSieving, maxNumberOfPassesToReturn, storageProxy, areaControlSet, populationControl, pDExistenceMap, overrides, liftParams) { }
public void AreaControlSet_Float_Rotation() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = siteModelCellsize * 2; double userOriginXY = 0; var rotation = 1.5708; // 90deg var areaControlSet = new AreaControlSet(false, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = siteModelCellsize / 2; double subGridWorldOriginY = siteModelCellsize / 2; var assignmentContext = new FilteredValueAssignmentContext(); var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, areaControlSet, siteModelCellsize, assignmentContext, out SubGridTreeBitmapSubGridBits sieveBitmask); Assert.True(sieveFilterInUse, "sieve filter should have been generated"); // 256/1024 set, first set at 0,0 Assert.True(sieveBitmask.CountBits() == 256, $"Incorrect count of bits set. Expected 256 but got {sieveBitmask.CountBits()}"); CheckProbePositions(assignmentContext.ProbePositions, false, 0.51, 0.68, 0.51, 0.68); }
/// <summary> /// Computes a bitmask used to sieve out only the cells that will be used in the query context. /// The sieved cells are the only cells processed and returned. All other cells will be null values, /// even if data is present for them that matches filtering and other conditions /// </summary> /// <param name="subGridWorldOriginY"></param> /// <param name="areaControlSet"></param> /// <param name="siteModelCellSize"></param> /// <param name="assignmentContext"></param> /// <param name="sieveBitmask"></param> /// <param name="subGridWorldOriginX"></param> /// <returns></returns> public static bool ComputeSieveBitmaskFloat(double subGridWorldOriginX, double subGridWorldOriginY, AreaControlSet areaControlSet, double siteModelCellSize, FilteredValueAssignmentContext assignmentContext, out SubGridTreeBitmapSubGridBits sieveBitmask) { sieveBitmask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); if (areaControlSet.PixelXWorldSize < siteModelCellSize && areaControlSet.PixelYWorldSize < siteModelCellSize) { return(false); } // Progress through the cells in the grid, starting from the southern most // row in the grid and progressing from the western end to the eastern end // (ie: bottom to top, left to right), taking into account grid offsets and // rotations specified in areaControlSet // Calculate the world coordinate location of the origin (bottom left corner) // and limits (top right corner) of this sub grid var subGridWorldLimitX = subGridWorldOriginX + SubGridTreeConsts.SubGridTreeDimension * siteModelCellSize; var subGridWorldLimitY = subGridWorldOriginY + SubGridTreeConsts.SubGridTreeDimension * siteModelCellSize; // Calculate the parameter to control skipping across a rotated grid with respect to // a grid projection north oriented sub grid InitialiseRotationAndBounds(areaControlSet, subGridWorldOriginX, subGridWorldOriginY, subGridWorldLimitX, subGridWorldLimitY, out var numRowsToScan, out var numColsToScan, out var stepNorthX, out var stepNorthY, out var stepEastX, out var stepEastY, out var firstScanPointEast, out var firstScanPointNorth); // Perform the walk across all probed locations determining the cells we want to // obtain values for and the probe locations. PerformScan(siteModelCellSize, assignmentContext, sieveBitmask, numRowsToScan, numColsToScan, stepNorthX, stepNorthY, stepEastX, stepEastY, subGridWorldOriginX, subGridWorldOriginY, firstScanPointEast, firstScanPointNorth); return(true); }
/// <summary> /// Serializes content from the writer /// </summary> public override void InternalFromBinary(IBinaryRawReader reader) { base.InternalFromBinary(reader); var version = VersionSerializationHelper.CheckVersionByte(reader, VERSION_NUMBER); if (version == 1) { RequestID = reader.ReadGuid() ?? Guid.Empty; GridDataType = (GridDataType)reader.ReadInt(); ProdDataMaskBytes = reader.ReadByteArray(); SurveyedSurfaceOnlyMaskBytes = reader.ReadByteArray(); IncludeSurveyedSurfaceInformation = reader.ReadBoolean(); AreaControlSet = new AreaControlSet(); AreaControlSet.FromBinary(reader); SubGridsRequestComputeStyle = (SubGridsRequestComputeStyle)reader.ReadInt(); } }
public void AreaControlSet_Float_WorldOriginPriorToCenterCell00() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; // for ComputeSieveFloat(): (differs to ComputeSieveInteger()) // subGridWorldOriginX is becomes the center of a cell // i.e. 0,0 is seen as center of cell 1,1; cellsize/2 is ALSO seen at on cell 0,0 double pixelWorldSizeOrIntervalXY = SubGridTreeConsts.DefaultCellSize * 2; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(false, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = siteModelCellsize / 2; double subGridWorldOriginY = siteModelCellsize / 2; var assignmentContext = new FilteredValueAssignmentContext(); var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, areaControlSet, siteModelCellsize, assignmentContext, out SubGridTreeBitmapSubGridBits sieveBitmask); Assert.True(sieveFilterInUse, "sieve filter should have been generated"); // 256/1024 set, first set at 1,1 Assert.True(sieveBitmask.CountBits() == 256, $"Incorrect count of bits set. Expected 256 but got {sieveBitmask.CountBits()}"); var rowXActual = sieveBitmask.RowToString(0); var rowXExpected = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; Assert.True(rowXExpected == rowXActual, "bitSet for row 0 is invalid"); rowXActual = sieveBitmask.RowToString(2); Assert.True(rowXExpected == rowXActual, "bitSet for row 2 is invalid"); rowXActual = sieveBitmask.RowToString(1); rowXExpected = " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1"; Assert.True(rowXExpected == rowXActual, "bitSet for row 1 is invalid"); rowXActual = sieveBitmask.RowToString(3); Assert.True(rowXExpected == rowXActual, "bitSet for row 3 is invalid"); }
public void AreaControlSet_Float_WorldOriginCenterCell00() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = siteModelCellsize * 2; double userOriginXY = 0; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(false, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = siteModelCellsize / 2; double subGridWorldOriginY = siteModelCellsize / 2; var assignmentContext = new FilteredValueAssignmentContext(); var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, areaControlSet, siteModelCellsize, assignmentContext, out SubGridTreeBitmapSubGridBits sieveBitmask); Assert.True(sieveFilterInUse, "sieve filter should have been generated"); // 256/1024 set, first set at 0,0 Assert.True(sieveBitmask.CountBits() == 256, $"Incorrect count of bits set. Expected 256 but got {sieveBitmask.CountBits()}"); var rowXActual = sieveBitmask.RowToString(0); var rowXExpected = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; Assert.True(rowXExpected == rowXActual, "bitSet for row 0 is invalid"); rowXActual = sieveBitmask.RowToString(2); Assert.True(rowXExpected == rowXActual, "bitSet for row 2 is invalid"); rowXActual = sieveBitmask.RowToString(1); rowXExpected = " 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1"; Assert.True(rowXExpected == rowXActual, "bitSet for row 1 is invalid"); rowXActual = sieveBitmask.RowToString(3); Assert.True(rowXExpected == rowXActual, "bitSet for row 3 is invalid"); Assert.True(Math.Abs(assignmentContext.ProbePositions[1, 1].XOffset - 0.51) < 0.001, "real world X offset for 1,1 is invalid"); Assert.True(Math.Abs(assignmentContext.ProbePositions[1, 1].YOffset - 0.51) < 0.001, "real world Y offset for 1,1 is invalid"); }
public void AreaControlSet_Float_UserOrigin() { double siteModelCellsize = SubGridTreeConsts.DefaultCellSize; double pixelWorldSizeOrIntervalXY = siteModelCellsize * 2; double userOriginXY = 1000; // i.e. easting/northing // siteModelCellsize * 30; var rotation = Consts.NullDouble; var areaControlSet = new AreaControlSet(false, pixelWorldSizeOrIntervalXY, pixelWorldSizeOrIntervalXY, userOriginXY, userOriginXY, rotation); double subGridWorldOriginX = siteModelCellsize / 2; double subGridWorldOriginY = siteModelCellsize / 2; var assignmentContext = new FilteredValueAssignmentContext(); var sieveFilterInUse = GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, areaControlSet, siteModelCellsize, assignmentContext, out SubGridTreeBitmapSubGridBits sieveBitmask); Assert.True(sieveFilterInUse, "sieve filter should have been generated"); // 256/1024 set, first set at 0,0 Assert.True(sieveBitmask.CountBits() == 256, $"Incorrect count of bits set. Expected 256 but got {sieveBitmask.CountBits()}"); var rowXActual = sieveBitmask.RowToString(0); var rowXExpected = " 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0 1 0"; Assert.True(rowXExpected == rowXActual, "bitSet for row 0 is invalid"); rowXActual = sieveBitmask.RowToString(2); Assert.True(rowXExpected == rowXActual, "bitSet for row 2 is invalid"); rowXActual = sieveBitmask.RowToString(1); rowXExpected = " 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; Assert.True(rowXExpected == rowXActual, "bitSet for row 1 is invalid"); rowXActual = sieveBitmask.RowToString(3); Assert.True(rowXExpected == rowXActual, "bitSet for row 3 is invalid"); CheckProbePositions(assignmentContext.ProbePositions, true, 0.23, 0.68, 0.23, 0.68); }
public ISubGridRetriever Instance(ISubGridsRequestArgument subGridsRequestArgument, ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pdExistenceMap, ITRexSpatialMemoryCacheContext[] subGridCacheContexts, IOverrideParameters overrides, ILiftParameters liftParams) { if (gridDataType == GridDataType.ProgressiveVolumes) { var retriever = new ProgressiveVolumesSubGridRetriever(siteModel, gridDataType, storageProxy, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, subGridCacheContexts != null, maxNumberOfPassesToReturn, areaControlSet, populationControl, pdExistenceMap, overrides, liftParams); if (subGridsRequestArgument is IProgressiveVolumesSubGridsRequestArgument argument) { retriever.StartDate = argument.StartDate; retriever.EndDate = argument.EndDate; retriever.Interval = argument.Interval; } else { throw new ArgumentException($"Argument passed to sub grid retriever factory for progressive volumes retriever construction is not an expected type: {subGridsRequestArgument.GetType()}"); } return(retriever); } else { var retriever = new SubGridRetriever(siteModel, gridDataType, storageProxy, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, subGridCacheContexts != null, maxNumberOfPassesToReturn, areaControlSet, populationControl, pdExistenceMap, overrides, liftParams); return(retriever); } }
/// <summary> /// For each point in the list, get the sub grid and extract productionData at the station/offset i.e pointOfInterest /// This could be optimized to get any poi from each sub grid before disposal /// </summary> private StationOffsetReportRequestResponse_ClusterCompute GetProductionData() { var result = new StationOffsetReportRequestResponse_ClusterCompute { ResultStatus = RequestErrorStatus.Unknown }; IDesignWrapper cutFillDesignWrapper = null; if (requestArgument.ReferenceDesign != null && requestArgument.ReferenceDesign.DesignID != Guid.Empty) { var cutFillDesign = siteModel.Designs.Locate(requestArgument.ReferenceDesign.DesignID); if (cutFillDesign == null) { throw new ArgumentException($"Design {requestArgument.ReferenceDesign.DesignID} not a recognized design in project {requestArgument.ProjectID}"); } cutFillDesignWrapper = new DesignWrapper(requestArgument.ReferenceDesign, cutFillDesign); } var existenceMap = siteModel.ExistenceMap; var utilities = DIContext.Obtain <IRequestorUtilities>(); var requestors = utilities.ConstructRequestors(null, siteModel, requestArgument.Overrides, requestArgument.LiftParams, utilities.ConstructRequestorIntermediaries(siteModel, requestArgument.Filters, true, GridDataType.CellProfile), AreaControlSet.CreateAreaControlSet(), existenceMap); // Obtain the primary partition map to allow this request to determine the elements it needs to process bool[] primaryPartitionMap = ImmutableSpatialAffinityPartitionMap.Instance().PrimaryPartitions(); SubGridTreeBitmapSubGridBits cellOverrideMask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); foreach (var point in requestArgument.Points) { // Determine the on-the-ground cell siteModel.Grid.CalculateIndexOfCellContainingPosition(point.Easting, point.Northing, out int OTGCellX, out int OTGCellY); var thisSubGridOrigin = new SubGridCellAddress(OTGCellX, OTGCellY); if (!primaryPartitionMap[thisSubGridOrigin.ToSpatialPartitionDescriptor()]) { continue; } // Get the sub grid relative cell location int cellX = OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask; int cellY = OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask; // Reach into the sub-grid request layer and retrieve an appropriate sub-grid cellOverrideMask.Clear(); cellOverrideMask.SetBit(cellX, cellY); requestors[0].CellOverrideMask = cellOverrideMask; // using the cell address get the index of cell in clientGrid var requestSubGridInternalResult = requestors[0].RequestSubGridInternal( thisSubGridOrigin, true, true); if (requestSubGridInternalResult.requestResult != ServerRequestResult.NoError) { Log.LogError($"Request for sub grid {thisSubGridOrigin} request failed with code {result}"); result.StationOffsetRows.Add(new StationOffsetRow(point.Station, point.Offset, point.Northing, point.Easting)); continue; } var hydratedPoint = ExtractRequiredValues(cutFillDesignWrapper, point, requestSubGridInternalResult.clientGrid as ClientCellProfileLeafSubgrid, cellX, cellY); result.StationOffsetRows.Add(hydratedPoint); } result.ResultStatus = RequestErrorStatus.OK; return(result); }
/// <summary> /// Builds a fully analyzed vector of profiled cells from the list of cell passed to it /// </summary> public override bool Analyze(List <SummaryVolumeProfileCell> profileCells, ISubGridSegmentCellPassIterator cellPassIterator) { Log.LogDebug($"Analyze Summary Volume ProfileCells. Processing {profileCells.Count}"); var CurrentSubgridOrigin = new SubGridCellAddress(int.MaxValue, int.MaxValue); ISubGrid SubGrid = null; IServerLeafSubGrid _SubGridAsLeaf = null; profileCell = null; // Construct the set of requestors to query elevation sub grids needed for the summary volume calculations. var filterSet = FilterUtilities.ConstructFilters(FilterSet, VolumeType); IntermediaryFilterRequired = filterSet.Filters.Length == 3; var utilities = DIContext.Obtain <IRequestorUtilities>(); Requestors = utilities.ConstructRequestors(null, SiteModel, Overrides, LiftParams, utilities.ConstructRequestorIntermediaries(SiteModel, filterSet, true, GridDataType.HeightAndTime), AreaControlSet.CreateAreaControlSet(), PDExistenceMap); var cellOverrideMask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); for (int I = 0; I < profileCells.Count; I++) { profileCell = profileCells[I]; // get sub grid origin for cell address var thisSubgridOrigin = new SubGridCellAddress(profileCell.OTGCellX >> SubGridTreeConsts.SubGridIndexBitsPerLevel, profileCell.OTGCellY >> SubGridTreeConsts.SubGridIndexBitsPerLevel); if (!CurrentSubgridOrigin.Equals(thisSubgridOrigin)) // if we have a new sub grid to fetch { // if we have an existing sub grid and a change in sub grid detected process the current sub grid profile cell list if (SubGrid != null) { ProcessSubGroup(new SubGridCellAddress(CurrentSubgridOrigin.X << SubGridTreeConsts.SubGridIndexBitsPerLevel, CurrentSubgridOrigin.Y << SubGridTreeConsts.SubGridIndexBitsPerLevel), PDExistenceMap[CurrentSubgridOrigin.X, CurrentSubgridOrigin.Y], cellOverrideMask); cellOverrideMask.Clear(); } SubGrid = null; cellCounter = 0; // Does the sub grid tree contain this node in it's existence map? if so get sub grid if (PDExistenceMap[thisSubgridOrigin.X, thisSubgridOrigin.Y]) { SubGrid = SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining (SiteModel.PrimaryStorageProxy, SiteModel.Grid, profileCell.OTGCellX, profileCell.OTGCellY, SiteModel.Grid.NumLevels, false, false); } _SubGridAsLeaf = SubGrid as ServerSubGridTreeLeaf; if (_SubGridAsLeaf == null) { continue; } CurrentSubgridOrigin = thisSubgridOrigin; // all good to proceed with this sub grid } profileCellList[cellCounter++] = profileCell; // add cell to list to process for this sub grid cellOverrideMask.SetBit(profileCell.OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask, profileCell.OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask); } if (cellCounter > 0 && SubGrid != null) // Make sure we process last list { ProcessSubGroup(new SubGridCellAddress(CurrentSubgridOrigin.X << SubGridTreeConsts.SubGridIndexBitsPerLevel, CurrentSubgridOrigin.Y << SubGridTreeConsts.SubGridIndexBitsPerLevel), PDExistenceMap[CurrentSubgridOrigin.X, CurrentSubgridOrigin.Y], cellOverrideMask); } return(true); }
/// <summary> /// Executor that implements requesting and rendering sub grid information to create the cell datum /// </summary> public async Task <CellPassesResponse> ExecuteAsync(CellPassesRequestArgument_ClusterCompute arg, SubGridSpatialAffinityKey key) { Log.LogInformation($"Performing Execute for DataModel:{arg.ProjectID}"); var result = new CellPassesResponse { ReturnCode = CellPassesReturnCode.Error }; var siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(arg.ProjectID); if (siteModel == null) { Log.LogError($"Failed to locate site model {arg.ProjectID}"); return(result); } var existenceMap = siteModel.ExistenceMap; var utilities = DIContext.Obtain <IRequestorUtilities>(); var requestors = utilities.ConstructRequestors(null, siteModel, arg.Overrides, arg.LiftParams, utilities.ConstructRequestorIntermediaries(siteModel, arg.Filters, true, GridDataType.CellPasses), AreaControlSet.CreateAreaControlSet(), existenceMap); // Get the sub grid relative cell location var cellX = arg.OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask; var cellY = arg.OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask; // Reach into the sub-grid request layer and retrieve an appropriate sub-grid var cellOverrideMask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); cellOverrideMask.SetBit(cellX, cellY); requestors[0].CellOverrideMask = cellOverrideMask; var thisSubGridOrigin = new SubGridCellAddress(arg.OTGCellX, arg.OTGCellY); var requestSubGridInternalResult = requestors[0].RequestSubGridInternal(thisSubGridOrigin, true, true); if (requestSubGridInternalResult.requestResult != ServerRequestResult.NoError) { if (requestSubGridInternalResult.requestResult == ServerRequestResult.SubGridNotFound) { result.ReturnCode = CellPassesReturnCode.NoDataFound; } else { Log.LogError($"Request for sub grid {thisSubGridOrigin} request failed with code {requestSubGridInternalResult.requestResult}"); } return(result); } if (!(requestSubGridInternalResult.clientGrid is ClientCellProfileAllPassesLeafSubgrid grid)) { Log.LogError($"Request for sub grid {thisSubGridOrigin} request failed due the grid return type being incorrect. Expected {typeof(ClientCellProfileAllPassesLeafSubgrid).Name}, but got {requestSubGridInternalResult.clientGrid.GetType().Name}"); return(result); } var cell = grid.Cells[cellX, cellY]; if (cell.TotalPasses > 0) { result.ReturnCode = CellPassesReturnCode.DataFound; for (var idx = 0; idx < cell.TotalPasses; idx++) { var cellPass = cell.CellPasses[idx]; result.CellPasses.Add(cellPass); } } else { result.ReturnCode = CellPassesReturnCode.NoDataFound; } return(result); }
private static void InitialiseRotationAndBounds(AreaControlSet areaControlSet, double subGridMinX, double subGridMinY, double subGridMaxX, double subGridMaxY, out int numRowsToScan, out int numColsToScan, out double stepNorthX, out double stepNorthY, out double stepEastX, out double stepEastY, out double firstScanPointEast, out double firstScanPointNorth) { var stepX = areaControlSet.PixelXWorldSize; var stepY = areaControlSet.PixelYWorldSize; // Take into account the effect of having to have a grid probe position at // the 'first point' defined in areaControlSet // Calculate the intra-interval offset that needs to be applied to align the // skip-stepping to that modified grid search var intraGridOffsetX = areaControlSet.UserOriginX - (Math.Floor(areaControlSet.UserOriginX / stepX) * stepX); var intraGridOffsetY = areaControlSet.UserOriginY - (Math.Floor(areaControlSet.UserOriginY / stepY) * stepY); if (areaControlSet.Rotation != Consts.NullDouble && areaControlSet.Rotation != 0) // Radians, north azimuth survey angle { var rotatedSubGridBoundary = new Fence(); // Create the rotated boundary by 'un-rotating' the sub grid world extents into a context // where the grid is itself not rotated GeometryHelper.RotatePointAbout(areaControlSet.Rotation, subGridMinX, subGridMinY, out var x, out var y, areaControlSet.UserOriginX, areaControlSet.UserOriginY); rotatedSubGridBoundary.Points.Add(new FencePoint(x, y)); GeometryHelper.RotatePointAbout(areaControlSet.Rotation, subGridMinX, subGridMaxY, out x, out y, areaControlSet.UserOriginX, areaControlSet.UserOriginY); rotatedSubGridBoundary.Points.Add(new FencePoint(x, y)); GeometryHelper.RotatePointAbout(areaControlSet.Rotation, subGridMaxX, subGridMaxY, out x, out y, areaControlSet.UserOriginX, areaControlSet.UserOriginY); rotatedSubGridBoundary.Points.Add(new FencePoint(x, y)); GeometryHelper.RotatePointAbout(areaControlSet.Rotation, subGridMaxX, subGridMinY, out x, out y, areaControlSet.UserOriginX, areaControlSet.UserOriginY); rotatedSubGridBoundary.Points.Add(new FencePoint(x, y)); rotatedSubGridBoundary.UpdateExtents(); firstScanPointEast = Math.Truncate(rotatedSubGridBoundary.MinX / stepX) * stepX + intraGridOffsetX; firstScanPointNorth = Math.Truncate(rotatedSubGridBoundary.MinY / stepY) * stepY + intraGridOffsetY; numRowsToScan = (int)Math.Ceiling((rotatedSubGridBoundary.MaxY - firstScanPointNorth) / stepY) + 1; numColsToScan = (int)Math.Ceiling((rotatedSubGridBoundary.MaxX - firstScanPointEast) / stepX) + 1; // Rotate the first scan point back to the context of the grid projection north oriented // sub grid world extents GeometryHelper.RotatePointAbout(-areaControlSet.Rotation, firstScanPointEast, firstScanPointNorth, out firstScanPointEast, out firstScanPointNorth, areaControlSet.UserOriginX, areaControlSet.UserOriginY); // Perform a 'unit' rotation of the StepX and StepY quantities about the // origin to define step quantities that orient the vector of probe position movement // to the rotated probe grid var sinOfRotation = Math.Sin(areaControlSet.Rotation); var cosOfRotation = Math.Cos(areaControlSet.Rotation); stepNorthY = cosOfRotation * stepY; stepNorthX = sinOfRotation * stepX; stepEastX = cosOfRotation * stepX; stepEastY = -sinOfRotation * stepY; } else { firstScanPointEast = Math.Truncate(subGridMinX / stepX) * stepX + intraGridOffsetX; firstScanPointNorth = Math.Truncate(subGridMinY / stepY) * stepY + intraGridOffsetY; numRowsToScan = (int)Math.Ceiling((subGridMaxY - firstScanPointNorth) / stepY) + 1; numColsToScan = (int)Math.Ceiling((subGridMaxX - firstScanPointEast) / stepX) + 1; stepNorthX = 0; stepNorthY = stepY; stepEastX = stepX; stepEastY = 0; } }
/// <summary> /// Computes a bitmask used to sieve out only the cells that will be used in the query context. /// The sieved cells are the only cells processed and returned. All other cells will be null values, /// even if data is present for them that matches filtering and other conditions /// </summary> /// <param name="subGridMoniker"></param> /// <param name="areaControlSet"></param> /// <param name="siteModelCellSize"></param> /// <param name="sieveBitmask"></param> /// <param name="subGridWorldOriginX"></param> /// <param name="subGridWorldOriginY"></param> /// <returns></returns> public static bool ComputeSieveBitmaskInteger(double subGridWorldOriginX, double subGridWorldOriginY, string subGridMoniker, AreaControlSet areaControlSet, double siteModelCellSize, out SubGridTreeBitmapSubGridBits sieveBitmask) { const int kMaxStepSize = 10000; sieveBitmask = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); /* TODO - add configuration item for VLPDPSNode_UseSkipStepComputationForWMSSubGridRequests * if (!VLPDSvcLocations.VLPDPSNode_UseSkipStepComputationForWMSSubGridRequests) * return false; */ if (areaControlSet.PixelXWorldSize < siteModelCellSize && areaControlSet.PixelYWorldSize < siteModelCellSize) { return(false); } // Progress through the cells in the grid, starting from the southern most // row in the grid and progressing from the western end to the eastern end // (ie: bottom to top, left to right) ///////////////// CalculateParameters; START double stepsPerPixelX = areaControlSet.PixelXWorldSize / siteModelCellSize; double stepsPerPixelY = areaControlSet.PixelYWorldSize / siteModelCellSize; // Note: integers int stepX = Math.Min(kMaxStepSize, Math.Max(1, (int)Math.Truncate(stepsPerPixelX))); int stepY = Math.Min(kMaxStepSize, Math.Max(1, (int)Math.Truncate(stepsPerPixelY))); double stepXIncrement = stepX * siteModelCellSize; double stepYIncrement = stepY * siteModelCellSize; double stepXIncrementOverTwo = stepXIncrement / 2; double stepYIncrementOverTwo = stepYIncrement / 2; ///////////////// CalculateParameters; END if (stepX < 2 && stepY < 2) { return(false); } if (stepX >= SubGridTreeConsts.SubGridTreeDimension && stepY >= SubGridTreeConsts.SubGridTreeDimension) { Log.LogDebug($"Skip value of {stepX}/{stepY} chosen for {subGridMoniker}"); } sieveBitmask.Clear(); // Calculate the world coordinate location of the origin (bottom left corner) of this sub grid //subGrid.CalculateWorldOrigin(out double subGridWorldOriginX, out double subGridWorldOriginY); // Skip-Iterate through the cells marking those cells that require values // calculate for them in the bitmask double temp = subGridWorldOriginY / stepYIncrement; double currentNorth = (Math.Truncate(temp) * stepYIncrement) - stepYIncrementOverTwo; int northRow = (int)Math.Floor((currentNorth - subGridWorldOriginY) / siteModelCellSize); while (northRow < 0) { northRow += stepY; } while (northRow < SubGridTreeConsts.SubGridTreeDimension) { temp = subGridWorldOriginX / stepXIncrement; double currentEast = (Math.Truncate(temp) * stepXIncrement) - stepXIncrementOverTwo; int eastCol = (int)Math.Floor((currentEast - subGridWorldOriginX) / siteModelCellSize); while (eastCol < 0) { eastCol += stepX; } while (eastCol < SubGridTreeConsts.SubGridTreeDimension) { sieveBitmask.SetBit(eastCol, northRow); eastCol += stepX; } northRow += stepY; } return(true); }