public void Test_SubGridTreeBitmapSubGridBitsTests_ClearBit() { // Test setting a bit on and off, at two corners to test boundary conditions SubGridTreeBitmapSubGridBits bits = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); bits.SetBit(0, 0); Assert.NotEqual(0U, bits.Bits[0]); Assert.Equal(1, bits.CountBits()); bits.ClearBit(0, 0); Assert.Equal(0U, bits.Bits[0]); Assert.Equal(0, bits.CountBits()); bits.SetBit(31, 31); Assert.NotEqual(0U, bits.Bits[31]); Assert.Equal(1, bits.CountBits()); bits.ClearBit(31, 31); Assert.Equal(0U, bits.Bits[31]); Assert.Equal(0, bits.CountBits()); }
public override bool PerformHeightAnnotation(SubGridTreeBitmapSubGridBits processingMap, IList filteredSurveyedSurfaces, bool returnEarliestFilteredCellPass, IClientLeafSubGrid surfaceElevationsSource, Func <int, int, float, bool> elevationRangeFilterLambda) { if (!(surfaceElevationsSource is ClientHeightAndTimeLeafSubGrid surfaceElevations)) { _log.LogError($"{nameof(ClientHeightAndTimeLeafSubGrid)}.{nameof(PerformHeightAnnotation)} not supplied a ClientHeightAndTimeLeafSubGrid instance, but an instance of {surfaceElevationsSource?.GetType().FullName}"); return(false); } // For all cells we wanted to request a surveyed surface elevation for, // update the cell elevation if a non null surveyed surface of appropriate time was computed // Note: The surveyed surface will return all cells in the requested sub grid, not just the ones indicated in the processing map // IE: It is unsafe to test for null top indicate not-filtered, use the processing map iterators to cover only those cells required processingMap.ForEachSetBit((x, y) => { var surveyedSurfaceCellHeight = surfaceElevations.Cells[x, y]; // ReSharper disable once CompareOfFloatsByEqualityOperator if (surveyedSurfaceCellHeight == Consts.NullHeight) { return; } // If we got back a surveyed surface elevation... var surveyedSurfaceCellTime = surfaceElevations.Times[x, y]; var prodHeight = Cells[x, y]; var prodTime = Times[x, y]; // Determine if the elevation from the surveyed surface data is required based on the production data elevation being null, and // the relative age of the measured surveyed surface elevation compared with a non-null production data height // ReSharper disable once CompareOfFloatsByEqualityOperator if (!(prodHeight == Consts.NullHeight || (returnEarliestFilteredCellPass ? surveyedSurfaceCellTime <prodTime : surveyedSurfaceCellTime> prodTime))) { // We didn't get a surveyed surface elevation, so clear the bit in the processing map to indicate there is no surveyed surface information present for it processingMap.ClearBit(x, y); return; } // Check if there is an elevation range filter in effect and whether the surveyed surface elevation data matches it if (elevationRangeFilterLambda != null) { if (!elevationRangeFilterLambda(x, y, surveyedSurfaceCellHeight)) { // We didn't get a surveyed surface elevation, so clear the bit in the processing map to indicate there is no surveyed surface information present for it processingMap.ClearBit(x, y); return; } } Cells[x, y] = surveyedSurfaceCellHeight; Times[x, y] = surveyedSurfaceCellTime; }); // if (ClientGrid_is_TICClientSubGridTreeLeaf_HeightAndTime) // ClientGridAsHeightAndTime.SurveyedSurfaceMap.Assign(ProcessingMap); return(true); }
public override bool UpdateProcessingMapForSurveyedSurfaces(SubGridTreeBitmapSubGridBits processingMap, IList filteredSurveyedSurfaces, bool returnEarliestFilteredCellPass) { if (!(filteredSurveyedSurfaces is ISurveyedSurfaces surveyedSurfaces)) { return(false); } processingMap.Assign(FilterMap); // If we're interested in a particular cell, but we don't have any surveyed surfaces later (or earlier) // than the cell production data pass time (depending on PassFilter.ReturnEarliestFilteredCellPass) // then there's no point in asking the Design Profiler service for an elevation processingMap.ForEachSetBit((x, y) => { // ReSharper disable once CompareOfFloatsByEqualityOperator if (Cells[x, y] != Consts.NullHeight && !(returnEarliestFilteredCellPass ? surveyedSurfaces.HasSurfaceEarlierThan(Times[x, y]) : surveyedSurfaces.HasSurfaceLaterThan(Times[x, y]))) { processingMap.ClearBit(x, y); } }); return(true); }
public override bool ComputeFilterPatch(double startStn, double endStn, double leftOffset, double rightOffset, SubGridTreeBitmapSubGridBits mask, SubGridTreeBitmapSubGridBits patch, double originX, double originY, double cellSize, double offset) { var Heights = new float[SubGridTreeConsts.SubGridTreeDimension, SubGridTreeConsts.SubGridTreeDimension]; if (InterpolateHeights(Heights, originX, originY, cellSize, offset)) { mask.ForEachSetBit((x, y) => { if (Heights[x, y] == Common.Consts.NullHeight) { mask.ClearBit(x, y); } }); patch.Assign(mask); //SIGLogMessage.PublishNoODS(Self, Format('Filter patch construction successful with %d bits', [patch.CountBits]), ...); return(true); } //SIGLogMessage.PublishNoODS(Self, Format('Filter patch construction failed...', []), ...); return(false); }
/// <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 void Test_SubGridTreeBitmapSubGridBitsTests_Operators_AND() { SubGridTreeBitmapSubGridBits bits1 = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Filled); SubGridTreeBitmapSubGridBits bits2 = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); Assert.Equal((bits1 & bits2), bits2); bits1.ClearBit(1, 1); Assert.NotEqual((bits1 & bits2), bits1); }
public void Test_SubGridTreeBitmapSubGridBitsTests_Operators_NOT() { SubGridTreeBitmapSubGridBits bits1 = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Filled); SubGridTreeBitmapSubGridBits bits2 = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); Assert.Equal(~bits1, bits2); Assert.Equal(bits1, ~bits2); bits1.ClearBit(1, 1); Assert.True((~bits1).BitSet(1, 1), "NOTing single bit did not flip it"); }
public void Test_SubGridTreeBitmapSubGridBitsTests_Operators_OR() { SubGridTreeBitmapSubGridBits bits1 = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Filled); SubGridTreeBitmapSubGridBits bits2 = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); Assert.Equal((bits1 | bits2), bits1); bits1.ClearBit(1, 1); Assert.Equal((bits1 | bits2), bits1); bits2.SetBit(1, 1); Assert.True((bits1 | bits2).IsFull(), "ORing after clearing/setting bits did not return full mask"); }
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); }
public static void ConstructSubgridSpatialAndPositionalMask(ILeafSubGrid SubGridAsLeaf, ISiteModel SiteModel, ICombinedFilter Filter, bool AHasOverrideSpatialCellRestriction, BoundingIntegerExtent2D AOverrideSpatialCellRestriction, SubGridTreeBitmapSubGridBits PDMask, SubGridTreeBitmapSubGridBits FilterMask) { if (Filter == null || !Filter.SpatialFilter.HasSpatialOrPositionalFilters) { PDMask.Fill(); FilterMask.Fill(); return; } var originX = SubGridAsLeaf.OriginX; var originY = SubGridAsLeaf.OriginY; var cellSize = SiteModel.CellSize; // Get the world location of the origin position SiteModel.Grid.GetCellCenterPosition(originX, originY, out var OX, out var OY); var SpatialFilter = Filter.SpatialFilter; // Attempt to satisfy the calculation below on the basis of the sub grid wholly residing in the override and filter spatial restrictions if (SpatialFilter.Fence.IncludesExtent(new BoundingWorldExtent3D(OX, OY, OX + cellSize * SubGridTreeConsts.SubGridTreeDimension, OY + cellSize * SubGridTreeConsts.SubGridTreeDimension))) { // The extent of the sub grid is wholly contained in the filter, therefore there is no need to iterate though all the cells // individually... FilterMask.Fill(); // ... unless there is an override spatial cell restriction that does not enclose the extent of the sub grid if (AHasOverrideSpatialCellRestriction && !AOverrideSpatialCellRestriction.Encloses(new BoundingIntegerExtent2D((int)originX, (int)originY, (int)originX + SubGridTreeConsts.SubGridTreeDimension, (int)originY + SubGridTreeConsts.SubGridTreeDimension))) { for (byte I = 0; I < SubGridTreeConsts.SubGridTreeDimension; I++) { for (byte J = 0; J < SubGridTreeConsts.SubGridTreeDimension; J++) { if (!AOverrideSpatialCellRestriction.Includes(originX + I, originY + J)) { FilterMask.ClearBit(I, J); } } } } } else { // Perform the calculation the long hand way // ... Idea: Invert row and column order of calculation below to get and set bits based on an entire column of bits FilterMask.Clear(); // Construct the filter mask based on the spatial and location (square/circle/polygonal) filtering double CX = OX; for (byte I = 0; I < SubGridTreeConsts.SubGridTreeDimension; I++) { int OriginXPlusI = originX + I; double CY = OY; // Set to the first row in the column about to be processed for (byte J = 0; J < SubGridTreeConsts.SubGridTreeDimension; J++) { if (AHasOverrideSpatialCellRestriction && !AOverrideSpatialCellRestriction.Includes((int)OriginXPlusI, (int)(originY + J))) { // Do nothing } else { // SiteModel.Grid.GetCellCenterPosition(OriginXPlusI, originY + J, out CX, out CY); if (SpatialFilter.IsCellInSelection(CX, CY)) { FilterMask.SetBit(I, J); } } CY += cellSize; // Move to next row } CX += cellSize; // Move to next column } } }
/// <summary> /// Performs the donkey work of the elevation patch calculation /// </summary> public IClientLeafSubGrid Execute(ISiteModel siteModel, int otgCellBottomLeftX, int otgCellBottomLeftY, double cellSize, SurveyedSurfacePatchType patchType, Guid[] includedSurveyedSurfaces, IDesignFiles designs, ISurveyedSurfaces surveyedSurfaces, SubGridTreeBitmapSubGridBits processingMap) { var calcResult = DesignProfilerRequestResult.UnknownError; try { if (!Enum.IsDefined(typeof(SurveyedSurfacePatchType), patchType)) { _log.LogError($"Unknown SurveyedSurfacePatchType: {patchType}, returning null"); return(null); } if (includedSurveyedSurfaces == null) { _log.LogError("Included surveyed surfaces list is null, returning null"); return(null); } if (processingMap == null) { _log.LogError("Supplied processing map is null, returning null"); return(null); } var patch = _clientLeafSubGridFactory.GetSubGridEx( patchType == SurveyedSurfacePatchType.CompositeElevations ? GridDataType.CompositeHeights : GridDataType.HeightAndTime, cellSize, SubGridTreeConsts.SubGridTreeLevels, otgCellBottomLeftX, otgCellBottomLeftY); // Assign var patchSingle = patchType != SurveyedSurfacePatchType.CompositeElevations ? patch as ClientHeightAndTimeLeafSubGrid : null; var patchComposite = patchType == SurveyedSurfacePatchType.CompositeElevations ? patch as ClientCompositeHeightsLeafSubgrid : null; patch.CalculateWorldOrigin(out var originX, out var originY); var halfCellSize = cellSize / 2; var originXPlusHalfCellSize = originX + halfCellSize; var originYPlusHalfCellSize = originY + halfCellSize; // Work down through the list of surfaces in the time ordering provided by the caller foreach (var surveyedSurfaceUid in includedSurveyedSurfaces) { if (processingMap.IsEmpty()) { break; } var thisSurveyedSurface = surveyedSurfaces.Locate(surveyedSurfaceUid); if (thisSurveyedSurface == null) { _log.LogError($"Surveyed surface {surveyedSurfaceUid} not found in site model, returning null"); calcResult = DesignProfilerRequestResult.FailedToLoadDesignFile; return(null); } // Lock & load the design var design = designs.Lock(thisSurveyedSurface.DesignDescriptor.DesignID, siteModel, cellSize, out _); if (design == null) { _log.LogError($"Failed to lock design file {thisSurveyedSurface.DesignDescriptor} in {nameof(CalculateSurfaceElevationPatch)}"); calcResult = DesignProfilerRequestResult.FailedToLoadDesignFile; return(null); } try { if (!design.HasElevationDataForSubGridPatch( otgCellBottomLeftX >> SubGridTreeConsts.SubGridIndexBitsPerLevel, otgCellBottomLeftY >> SubGridTreeConsts.SubGridIndexBitsPerLevel)) { continue; } var asAtDate = thisSurveyedSurface.AsAtDate.Ticks; var hint = -1; // Walk across the sub grid checking for a design elevation for each appropriate cell // based on the processing bit mask passed in processingMap.ForEachSetBit((x, y) => { // If we can interpolate a height for the requested cell, then update the cell height // and decrement the bit count so that we know when we've handled all the requested cells if (design.InterpolateHeight(ref hint, originXPlusHalfCellSize + cellSize * x, originYPlusHalfCellSize + cellSize * y, 0, out var z)) { // Check for composite elevation processing if (patchType == SurveyedSurfacePatchType.CompositeElevations) { // Set the first elevation if not already set if (patchComposite.Cells[x, y].FirstHeightTime == 0) { patchComposite.Cells[x, y].FirstHeightTime = asAtDate; patchComposite.Cells[x, y].FirstHeight = (float)z; } // Always set the latest elevation (surfaces ordered by increasing date) patchComposite.Cells[x, y].LastHeightTime = asAtDate; patchComposite.Cells[x, y].LastHeight = (float)z; // Update the lowest height if (patchComposite.Cells[x, y].LowestHeightTime == 0 || patchComposite.Cells[x, y].LowestHeight > z) { patchComposite.Cells[x, y].LowestHeightTime = asAtDate; patchComposite.Cells[x, y].LowestHeight = (float)z; } // Update the highest height if (patchComposite.Cells[x, y].HighestHeightTime == 0 || patchComposite.Cells[x, y].HighestHeight > z) { patchComposite.Cells[x, y].HighestHeightTime = asAtDate; patchComposite.Cells[x, y].HighestHeight = (float)z; } } else // earliest/latest singular value processing { patchSingle.Times[x, y] = asAtDate; patchSingle.Cells[x, y] = (float)z; } } // Only clear the processing bit if earliest or latest information is wanted from the surveyed surfaces if (patchType != SurveyedSurfacePatchType.CompositeElevations) { processingMap.ClearBit(x, y); } return(true); }); } finally { designs.UnLock(thisSurveyedSurface.DesignDescriptor.DesignID, design); } } calcResult = DesignProfilerRequestResult.OK; return(patch); } catch (Exception e) { _log.LogError(e, $"Exception occurred calculating surveyed surface patch, calcResult = {calcResult}"); return(null); } }