Example #1
0
        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");
        }
Example #2
0
        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));
        }
Example #3
0
        /// <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);
        }
Example #4
0
        /// <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);
        }