/// <summary> /// Constructs a mask using all spatial filtering elements active in the supplied filter /// </summary> public static bool ConstructSubGridCellFilterMask(ISiteModel siteModel, SubGridCellAddress currentSubGridOrigin, InterceptList intercepts, int fromProfileCellIndex, SubGridTreeBitmapSubGridBits mask, ICellSpatialFilter cellFilter, IDesign surfaceDesignMaskDesign) { ConstructSubGridSpatialAndPositionalMask(currentSubGridOrigin, intercepts, fromProfileCellIndex, mask, cellFilter, siteModel.Grid); // If the filter contains an alignment design mask filter then compute this and AND it with the // mask calculated in the step above to derive the final required filter mask if (cellFilter.HasAlignmentDesignMask()) { if (cellFilter.AlignmentFence.IsNull()) // Should have been done in ASNode but if not { throw new ArgumentException($"Spatial filter does not contained pre-prepared alignment fence for design {cellFilter.AlignmentDesignMaskDesignUID}"); } var tree = siteModel.Grid; // Go over set bits and determine if they are in Design fence boundary mask.ForEachSetBit((x, y) => { tree.GetCellCenterPosition(currentSubGridOrigin.X + x, currentSubGridOrigin.Y + y, out var cx, out var cy); if (!cellFilter.AlignmentFence.IncludesPoint(cx, cy)) { mask.ClearBit(x, y); // remove interest as its not in design boundary } }); } // If the filter contains a design mask filter then compute this and AND it with the // mask calculated in the step above to derive the final required filter mask if (surfaceDesignMaskDesign != null) { var getFilterMaskResult = surfaceDesignMaskDesign.GetFilterMaskViaLocalCompute(siteModel, currentSubGridOrigin, siteModel.CellSize); if (getFilterMaskResult.errorCode == DesignProfilerRequestResult.OK || getFilterMaskResult.errorCode == DesignProfilerRequestResult.NoElevationsInRequestedPatch) { if (getFilterMaskResult.filterMask == null) { _log.LogWarning("FilterMask null in response from surfaceDesignMaskDesign.GetFilterMask, ignoring it's contribution to filter mask"); } else { mask.AndWith(getFilterMaskResult.filterMask); } } else { _log.LogError($"Call (A2) to {nameof(ConstructSubGridCellFilterMask)} returned error result {getFilterMaskResult.errorCode} for {cellFilter.SurfaceDesignMaskDesignUid}"); return(false); } } return(true); }
public static bool ConstructSubGridCellFilterMask(ILeafSubGrid SubGridAsLeaf, ISiteModel SiteModel, ICombinedFilter Filter, SubGridTreeBitmapSubGridBits CellOverrideMask, bool AHasOverrideSpatialCellRestriction, BoundingIntegerExtent2D AOverrideSpatialCellRestriction, SubGridTreeBitmapSubGridBits PDMask, SubGridTreeBitmapSubGridBits FilterMask) { ConstructSubgridSpatialAndPositionalMask(SubGridAsLeaf, SiteModel, Filter, AHasOverrideSpatialCellRestriction, AOverrideSpatialCellRestriction, PDMask, FilterMask); // Apply any override mask supplied by the caller. If all bits are required in the override, // then a filled mask should be supplied... PDMask.AndWith(CellOverrideMask); // If the filter contains a design mask filter then compute this and AND it with the // mask calculated in the step above to derive the final required filter mask if (Filter != null && Filter.SpatialFilter.HasAlignmentDesignMask()) { if (Filter.SpatialFilter.AlignmentFence.IsNull()) // Should have been done in ASNode but if not { throw new ArgumentException($"Spatial filter does not contained pre-prepared alignment fence for design {Filter.SpatialFilter.AlignmentDesignMaskDesignUID}"); } // Go over set bits and determine if they are in Design fence boundary FilterMask.ForEachSetBit((X, Y) => { SiteModel.Grid.GetCellCenterPosition(SubGridAsLeaf.OriginX + X, SubGridAsLeaf.OriginY + Y, out var CX, out var CY); if (!Filter.SpatialFilter.AlignmentFence.IncludesPoint(CX, CY)) { FilterMask.ClearBit(X, Y); // remove interest as its not in design boundary } }); } PDMask.AndWith(FilterMask); return(true); }
/// <summary> /// Orchestrates the mainline work of analyzing cell and cell pass information to create a client sub grid (heights, CMV, MDP etc) /// based on filter and other information established in the class /// </summary> /// <param name="clientGrid"></param> /// <param name="cellOverrideMask"></param> /// <returns></returns> public virtual ServerRequestResult RetrieveSubGrid(IClientLeafSubGrid clientGrid, SubGridTreeBitmapSubGridBits cellOverrideMask, out bool sieveFilterInUse, Func <ServerRequestResult> computeSpatialFilterMaskAndClientProdDataMap) { sieveFilterInUse = false; if (!Utilities.DerivedGridDataTypesAreCompatible(_gridDataType, clientGrid.GridDataType)) { throw new TRexSubGridProcessingException($"Grid data type of client leaf sub grid [{clientGrid.GridDataType}] is not compatible with the grid data type of retriever [{_gridDataType}]"); } var result = ServerRequestResult.UnknownError; // SIGLogMessage.PublishNoODS(Nil, Format('In RetrieveSubGrid: Active pass filters = %s, Active cell filters = %s', [PassFilter.ActiveFiltersText, CellFilter.ActiveFiltersText])); // Set up class local state for other methods to access _clientGrid = clientGrid; _clientGridAsLeaf = clientGrid as ClientLeafSubGrid; _canUseGlobalLatestCells &= !(_gridDataType == GridDataType.CCV || _gridDataType == GridDataType.CCVPercent) && _liftParams.CCVSummaryTypes != CCVSummaryTypes.None && !(_gridDataType == GridDataType.MDP || _gridDataType == GridDataType.MDPPercent) && _liftParams.MDPSummaryTypes != MDPSummaryTypes.None && !(_gridDataType == GridDataType.CCA || _gridDataType == GridDataType.CCAPercent) && !(_gridDataType == GridDataType.CellProfile || _gridDataType == GridDataType.PassCount || _gridDataType == GridDataType.CellPasses || _gridDataType == GridDataType.MachineSpeed || _gridDataType == GridDataType.CCVPercentChange || _gridDataType == GridDataType.MachineSpeedTarget || _gridDataType == GridDataType.CCVPercentChangeIgnoredTopNullValue); // Support for lazy construction of any required profiling infrastructure if (_clientGrid.WantsLiftProcessingResults() && _profiler == null) { // Some display types require lift processing to be able to select the // appropriate cell pass containing the filtered value required. _profiler = DIContext.Obtain <IProfilerBuilder <ProfileCell> >(); //TODO: should referenceDesignWrapper be null here or be passed through from args? _profiler.Configure(ProfileStyle.CellPasses, _siteModel, _pdExistenceMap, _gridDataType, new FilterSet(_filter), null, _populationControl, new CellPassFastEventLookerUpper(_siteModel), VolumeComputationType.None, _overrides, _liftParams); _cellProfile = new ProfileCell(); // 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.CellProfile = _cellProfile; } try { // Ensure pass type filter is set correctly if (_filter.AttributeFilter.HasPassTypeFilter) { if ((_filter.AttributeFilter.PassTypeSet & (PassTypeSet.Front | PassTypeSet.Rear)) == PassTypeSet.Front) { _filter.AttributeFilter.PassTypeSet |= PassTypeSet.Rear; // these two types go together as half passes } } // ... unless we can use the last pass grid to satisfy the query if (_canUseGlobalLatestCells && !_filter.AttributeFilter.HasElevationRangeFilter && !_clientGrid.WantsLiftProcessingResults() && !_filter.AttributeFilter.HasElevationMappingModeFilter && !(_filter.AttributeFilter.HasElevationTypeFilter && (_filter.AttributeFilter.ElevationType == ElevationType.Highest || _filter.AttributeFilter.ElevationType == ElevationType.Lowest)) && !(_gridDataType == GridDataType.PassCount || _gridDataType == GridDataType.Temperature || _gridDataType == GridDataType.CellProfile || _gridDataType == GridDataType.CellPasses || _gridDataType == GridDataType.MachineSpeed)) { _useLastPassGrid = true; } // First get the sub grid we are interested in // SIGLogMessage.PublishNoODS(Nil, Format('Begin LocateSubGridContaining at %dx%d', [clientGrid.OriginX, clientGrid.OriginY])); _subGrid = SubGridTrees.Server.Utilities.SubGridUtilities.LocateSubGridContaining(_storageProxy, _siteModel.Grid, clientGrid.OriginX, clientGrid.OriginY, _siteModel.Grid.NumLevels, false, false); // SIGLogMessage.PublishNoODS(Nil, Format('End LocateSubGridContaining at %dx%d', [clientGrid.OriginX, clientGrid.Origin])); if (_subGrid == null) // This should never really happen, but we'll be polite about it { Log.LogWarning( $"Sub grid address (CellX={clientGrid.OriginX}, CellY={clientGrid.OriginY}) passed to LocateSubGridContaining() from RetrieveSubGrid() did not match an existing sub grid in the data model. Returning SubGridNotFound as response with a null sub grid reference."); return(ServerRequestResult.SubGridNotFound); } // Now process the contents of that sub grid into the sub grid to be returned to the client. if (!_subGrid.IsLeafSubGrid()) { Log.LogInformation("Requests of node sub grids in the server sub grid are not yet supported"); return(result); } if (!(_subGrid is IServerLeafSubGrid)) { Log.LogError($"_SubGrid {_subGrid.Moniker()} is not a server grid leaf node"); return(result); } // SIGLogMessage.PublishNoODS(Nil, Format('Getting sub grid leaf at %dx%d', [clientGrid.OriginX, clientGrid.OriginY])); _subGridAsLeaf = (IServerLeafSubGrid)_subGrid; _globalLatestCells = _subGridAsLeaf.Directory.GlobalLatestCells; if (PruneSubGridRetrievalHere()) { return(ServerRequestResult.NoError); } // SIGLogMessage.PublishNoODS(Nil, Format('Setup for stripe iteration at %dx%d', [clientGrid.OriginX, clientGrid.OriginY])); SetupForCellPassStackExamination(); // Determine if a sieve filter is required for the sub grid where the sieve matches // the X and Y pixel world size (used for WMS tile computation) _subGrid.CalculateWorldOrigin(out var subGridWorldOriginX, out var subGridWorldOriginY); sieveFilterInUse = _areaControlSet.UseIntegerAlgorithm ? GridRotationUtilities.ComputeSieveBitmaskInteger(subGridWorldOriginX, subGridWorldOriginY, _subGrid.Moniker(), _areaControlSet, _siteModel.CellSize, out _sieveBitmask) : GridRotationUtilities.ComputeSieveBitmaskFloat(subGridWorldOriginX, subGridWorldOriginY, _areaControlSet, _siteModel.CellSize, _assignmentContext, out _sieveBitmask); //if (Debug_ExtremeLogSwitchC) Log.LogDebug($"Performing stripe iteration at {clientGrid.OriginX}x{clientGrid.OriginY}"); if (computeSpatialFilterMaskAndClientProdDataMap != null) { _clientGrid.ProdDataMap.Assign(_subGridAsLeaf.Directory.GlobalLatestCells.PassDataExistenceMap); var innerResult = computeSpatialFilterMaskAndClientProdDataMap(); if (innerResult != ServerRequestResult.NoError) { return(innerResult); } } // Before iterating over stripes of this sub grid, compute a scan map detailing to the best of our current // knowledge, which cells need to be visited so that only cells the filter wants and which are actually // present in the data set are requested. If the intent is to store the result in a cache then ensure the // entire content is requested for the sub grid. if (_prepareGridForCacheStorageIfNoSieving) { _aggregatedCellScanMap.Fill(); } else { _aggregatedCellScanMap.OrWith(_globalLatestCells.PassDataExistenceMap); if (sieveFilterInUse) { _aggregatedCellScanMap.AndWith(_sieveBitmask); // ... and which are required by any sieve mask } _aggregatedCellScanMap.AndWith(_clientGridAsLeaf.ProdDataMap); // ... and which are in the required production data map _aggregatedCellScanMap.AndWith(_clientGridAsLeaf.FilterMap); // ... and which are in the required filter map } // Iterate over the stripes in the sub grid processing each one in turn. for (byte i = 0; i < SubGridTreeConsts.SubGridTreeDimension; i++) { RetrieveSubGridStripe(i); } //if Debug_ExtremeLogSwitchC then Log.LogDebug($"Stripe iteration complete at {clientGrid.OriginX}x{clientGrid.OriginY}"); result = ServerRequestResult.NoError; } catch (Exception e) { Log.LogError(e, $"Exception occurred in {nameof(RetrieveSubGrid)}"); throw; } return(result); }