public void Test_SubGridTreeBitmapSubGridBitsTests_ForEach_Action() { // Test iteration action for empty, full and arbitrary masks SubGridTreeBitmapSubGridBits bits = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Filled); int sum; sum = 0; bits.ForEach((x, y) => { if (bits.BitSet(x, y)) { sum++; } }); Assert.True(sum == bits.CountBits() && sum == SubGridTreeConsts.CellsPerSubGrid, "Summation via ForEach on full mask did not give expected result"); sum = 0; bits.Clear(); bits.ForEach((x, y) => { if (bits.BitSet(x, y)) { sum++; } }); Assert.True(sum == bits.CountBits() && sum == 0, "Summation via ForEach on empty mask did not give expected result"); sum = 0; bits.SetBit(1, 1); bits.ForEach((x, y) => { if (bits.BitSet(x, y)) { sum++; } }); Assert.True(sum == bits.CountBits() && sum == 1, "Summation via ForEach on mask with single bit set at (1, 1) did not give expected result"); }
public void Test_SubGridTreeBitmapSubGridBitsTests_BitSet_Uint() { // Test testing a bit is on or off, at two corners to test boundary conditions SubGridTreeBitmapSubGridBits bits = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); Assert.False(bits.BitSet(0, 0U)); Assert.False(bits.BitSet(31, 31U)); bits.Fill(); Assert.True(bits.BitSet(0, 0U)); Assert.True(bits.BitSet(31, 31U)); }
/// <summary> /// Constructs a vector of cells in profileCells along the path of the profile geometry containing in nEECoords /// </summary> public bool Build(XYZ[] nEECoords, List <T> profileCells) { NEECoords = nEECoords; ProfileCells = profileCells; CellSize = SiteModel.CellSize; CurrStationPos = 0; CurrentSubgridOrigin = new SubGridCellAddress(int.MaxValue, int.MaxValue); ReturnDesignElevation = CutFillDesignWrapper?.Design != null; DesignElevations = null; // Obtain the primary partition map to allow this request to determine the elements it needs to process bool[] primaryPartitionMap = ImmutableSpatialAffinityPartitionMap.Instance().PrimaryPartitions(); for (int loopBound = NEECoords.Length - 1, I = 0; I < loopBound; I++) { StartX = NEECoords[I].X; StartY = NEECoords[I].Y; StartStation = NEECoords[I].Z; EndX = NEECoords[I + 1].X; EndY = NEECoords[I + 1].Y; EndStation = NEECoords[I + 1].Z; if (I == 0) // Add start point of profile line to intercept list { CurrStationPos = SlicerToolUsed ? 0 : NEECoords[I].Z; // alignment profiles pass in station for more accuracy VtHzIntercepts.AddPoint(StartX, StartY, CurrStationPos); } Distance = SlicerToolUsed ? MathUtilities.Hypot(EndX - StartX, EndY - StartY) // station is not passed so compute : EndStation - StartStation; // use precise station passed if (Distance == 0) // if we have two points the same { continue; } // Get all intercepts between profile line and cell boundaries for this segment CalculateHorizontalIntercepts(CurrStationPos); // pass the distance down alignment this segment starts CalculateVerticalIntercepts(CurrStationPos); CurrStationPos += Distance; // add distance to current station } // Merge vertical and horizontal cell boundary/profile line intercepts VtHzIntercepts.MergeInterceptLists(VtIntercepts, HzIntercepts); // Add end point of profile line to intercept list VtHzIntercepts.AddPoint(EndX, EndY, CurrStationPos); // Update each intercept with it's midpoint and intercept length // i.e. the midpoint on the line between one intercept and the next one // and the length between those intercepts VtHzIntercepts.UpdateMergedListInterceptMidPoints(); if (VtHzIntercepts.Count > ProfileCells.Capacity) { ProfileCells.Capacity = VtHzIntercepts.Count; } // Iterate over all intercepts calculating the results for each cell that lies in // a subgrid handled by this node for (int i = 0; i < VtHzIntercepts.Count; i++) { if (Aborted) { return(false); } // Determine the on-the-ground cell underneath the midpoint of each intercept line SiteModel.Grid.CalculateIndexOfCellContainingPosition(VtHzIntercepts.Items[i].MidPointX, VtHzIntercepts.Items[i].MidPointY, out OTGCellX, out OTGCellY); ThisSubgridOrigin = new SubGridCellAddress(OTGCellX & ~SubGridTreeConsts.SubGridLocalKeyMask, OTGCellY & ~SubGridTreeConsts.SubGridLocalKeyMask); if (!CurrentSubgridOrigin.Equals(ThisSubgridOrigin)) { if (!primaryPartitionMap[ThisSubgridOrigin.ToSpatialPartitionDescriptor()]) { continue; } CurrentSubgridOrigin = ThisSubgridOrigin; if (!ProfileFilterMask.ConstructSubGridCellFilterMask(SiteModel, CurrentSubgridOrigin, VtHzIntercepts, i, FilterMask, CellFilter, SurfaceDesignMaskDesign)) { continue; } if (ReturnDesignElevation && CutFillDesignWrapper?.Design != null) // cut fill profile request then get elevation at same spot along design { var getDesignHeightsResult = CutFillDesignWrapper.Design.GetDesignHeightsViaLocalCompute(SiteModel, CutFillDesignWrapper.Offset, new SubGridCellAddress(OTGCellX, OTGCellY), CellSize); DesignElevations = getDesignHeightsResult.designHeights; DesignResult = getDesignHeightsResult.errorCode; if (DesignResult != DesignProfilerRequestResult.OK && DesignResult != DesignProfilerRequestResult.NoElevationsInRequestedPatch) { continue; } if (DesignResult == DesignProfilerRequestResult.NoElevationsInRequestedPatch) { DesignElevations = null; // force a null height to be written } } } if (FilterMask.BitSet(OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask, OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask)) { AddCellPassesDataToList(OTGCellX, OTGCellY, VtHzIntercepts.Items[i].ProfileItemIndex, VtHzIntercepts.Items[i].InterceptLength); } } Log.LogInformation($"CellProfileBuilder constructed a vector of {VtHzIntercepts.Count} vertices"); return(true); }
/// <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); }