public void Test_SubGridTreeBitmapSubGridBitsTests_SetBitValue() { // Test setting a bit on and off, at two corners to test boundary conditions SubGridTreeBitmapSubGridBits bits = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); bits.SetBitValue(0, 0, true); Assert.NotEqual(0U, bits.Bits[0]); Assert.Equal(1, bits.CountBits()); bits.SetBitValue(0, 0, false); Assert.Equal(0U, bits.Bits[0]); Assert.Equal(0, bits.CountBits()); bits.SetBitValue(31, 31, true); Assert.NotEqual(0U, bits.Bits[31]); Assert.Equal(1, bits.CountBits()); bits.SetBitValue(31, 31, false); Assert.Equal(0U, bits.Bits[31]); Assert.Equal(0, bits.CountBits()); }
/// <summary> /// Computes a filter patch for a sub grid with respect to the alignment and a station/offset range over the alignment. /// Note: This is a CPU intensive operation. TRex currently uses an approach of polygonal spatial filtering with a boundary /// computed from the alignment geometry and station/offset bounds. /// </summary> 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 leftOffsetValue = -leftOffset; var rightOffsetValue = rightOffset; if (leftOffsetValue > rightOffsetValue) { MinMax.Swap(ref leftOffsetValue, ref rightOffsetValue); } // SIGLogMessage.PublishNoODS(Self, Format('Constructing filter patch for Stn:%.3f-%.3f, Ofs:%.3f-%.3f, originX:%.3f, originY:%.3f', // [startStn, endStn, LeftOffsetValue, RightOffsetValue, originX, originY])); if (_data == null) { _log.LogError("No data element provided to SVL filter patch calculation"); return(false); } patch.Clear(); // Check the corners of the sub grid. If all are out of the offset range then assume // none of the cells are applicable. All four corners need to be on the same side of the // alignment in terms of offset to fail the sub grid. var cornersOutOfOffsetRange = 0; var cornersOutOfOffsetRangeSign = 0; var originXPlusHalfCellSize = originX + cellSize / 2; var originYPlusHalfCellSize = originY + cellSize / 2; for (var i = 0; i < _corners.Length; i++) { _data.ComputeStnOfs(originXPlusHalfCellSize + _corners[i].X * cellSize, originYPlusHalfCellSize + _corners[i].Y * cellSize, out var stn, out var ofs); if (!(stn != Consts.NullDouble && ofs != Consts.NullDouble && Range.InRange(stn, startStn, endStn)) && !Range.InRange(ofs, leftOffsetValue, rightOffsetValue)) { if (i == 0) { cornersOutOfOffsetRangeSign = Math.Sign(ofs); } if (cornersOutOfOffsetRangeSign == Math.Sign(ofs)) { cornersOutOfOffsetRange++; } else { break; } } } if (cornersOutOfOffsetRange == _corners.Length) { // Return success with the empty patch //SIGLogMessage.PublishNoODS(Self, 'All corners of patch exceed stn:ofs boundary'); return(true); } // Iterate across the cells in the mask computing and checking the stn:ofs of // each point using the previously successful element as a hint for the next // computation for (var i = 0; i < SubGridTreeConsts.SubGridTreeDimension; i++) { for (var j = 0; j < SubGridTreeConsts.SubGridTreeDimension; j++) { if (!mask.BitSet(i, j)) { continue; } // Force element to be nil for all calculation until we resolve the issue // of an in appropriate element 'capturing' the focus and then being used to // calculate inappropriate offsets due to it's station range covering the // points being computed. NFFStationedLineworkEntity element = null; _data.ComputeStnOfs(originXPlusHalfCellSize + i * cellSize, originYPlusHalfCellSize + j * cellSize, out var stn, out var ofs, ref element); if (stn != Consts.NullDouble && ofs != Consts.NullDouble) { patch.SetBitValue(i, j, Range.InRange(stn, startStn, endStn) && Range.InRange(ofs, leftOffsetValue, rightOffsetValue)); } } } // SIGLogMessage.PublishNoODS(Self, Format('Filter patch construction successful with %d bits', [patch.CountBits])); return(true); }