Пример #1
0
        private ISiteModel BuildModelForSingleCellProgressiveVolume(int numCellPasses, DateTime baseTime, TimeSpan timeIncrement, float baseHeight, float heightIncrement)
        {
            var dummy = new ClientHeightLeafSubGrid(); // Ensure NullCells is intialised for this class,

            var siteModel             = DITAGFileAndSubGridRequestsWithIgniteFixture.NewEmptyModel();
            var bulldozerMachineIndex = siteModel.Machines.Locate("Bulldozer", false).InternalSiteModelMachineIndex;

            var cellPasses = Enumerable.Range(0, numCellPasses).Select(x =>
                                                                       new CellPass {
                InternalSiteModelMachineIndex = bulldozerMachineIndex, Time = baseTime + x * timeIncrement, Height = baseHeight + x * heightIncrement, PassType = PassType.Front
            }).ToList();

            // Ensure the machine the cell passes are being added to has start and stop evens bracketing the cell passes
            siteModel.MachinesTargetValues[bulldozerMachineIndex].StartEndRecordedDataEvents.PutValueAtDate(baseTime, ProductionEventType.StartEvent);
            siteModel.MachinesTargetValues[bulldozerMachineIndex].StartEndRecordedDataEvents.PutValueAtDate(baseTime + (numCellPasses - 1) * timeIncrement, ProductionEventType.EndEvent);

            siteModel.MachinesTargetValues[bulldozerMachineIndex].SaveMachineEventsToPersistentStore(siteModel.PrimaryStorageProxy);

            DITAGFileAndSubGridRequestsFixture.AddSingleCellWithPasses
                (siteModel, SubGridTreeConsts.DefaultIndexOriginOffset, SubGridTreeConsts.DefaultIndexOriginOffset, cellPasses, 1, cellPasses.Count());

            DITAGFileAndSubGridRequestsFixture.ConvertSiteModelToImmutable(siteModel);

            return(siteModel);
        }
Пример #2
0
        private ClientLeafSubGrid NewClientSubGrid()
        {
            var subGrid = new ClientHeightLeafSubGrid
            {
                OriginX = SubGridTreeConsts.DefaultIndexOriginOffset,
                OriginY = SubGridTreeConsts.DefaultIndexOriginOffset
            };

            subGrid.FillWithTestPattern();

            return(subGrid);
        }
Пример #3
0
        public void Test_HeightClientLeafSubGridTests_SetToZero()
        {
            ClientHeightLeafSubGrid subgrid = new ClientHeightLeafSubGrid(null, null, SubGridTreeConsts.SubGridTreeLevels, 1, SubGridTreeConsts.DefaultIndexOriginOffset);

            subgrid.SetToZeroHeight();

            Assert.Equal((int)subgrid.CountNonNullCells(), SubGridTreeConsts.CellsPerSubGrid);

            int NumEqualZero = 0;

            ClientHeightLeafSubGrid.ForEachStatic((x, y) =>
            {
                if (subgrid.Cells[x, y] == 0.0)
                {
                    NumEqualZero++;
                }
            });

            Assert.Equal((int)NumEqualZero, SubGridTreeConsts.CellsPerSubGrid);
        }
Пример #4
0
        public void Test_PatchTask_TransferResponse()
        {
            var pipeLine = new Mock <ISubGridPipelineBase>();

            pipeLine.Setup(mk => mk.Aborted).Returns(false);

            PatchTask task = new PatchTask
            {
                PipeLine = pipeLine.Object
            };

            ClientHeightLeafSubGrid transferSubgrid = new ClientHeightLeafSubGrid(null, null, 0, 1, 0);

            task.TransferResponse(new IClientLeafSubGrid[] { transferSubgrid });

            Assert.True(task.PatchSubGrids.Count == 1,
                        $"Count of transferred subgrids not 1 as expected (= {task.PatchSubGrids.Count}");
            Assert.True(task.PatchSubGrids[0] == transferSubgrid,
                        $"Transferred subgrid is not the same as the one passed into the task.");
        }
Пример #5
0
        public void Test_ElevationStatisticsAggregator_ProcessResult_NoAggregation()
        {
            var aggregator = new ElevationStatisticsAggregator();

            var clientGrid = new ClientHeightLeafSubGrid();

            clientGrid.FillWithTestPattern();

            var dLength = clientGrid.Cells.Length;

            aggregator.CellSize = TestConsts.CELL_SIZE;

            IClientLeafSubGrid[][] subGrids = new[] { new[] { clientGrid } };

            aggregator.ProcessSubGridResult(subGrids);

            Assert.True(aggregator.CellsScanned == dLength, "Invalid value for CellsScanned.");
            Assert.True(aggregator.CellsUsed == dLength, "Invalid value for CellsUsed.");
            Assert.True(Math.Abs(aggregator.CoverageArea - dLength * Math.Pow(aggregator.CellSize, 2)) < Consts.TOLERANCE_AREA, "Invalid value for CoverageArea.");
            Assert.True(Math.Abs(aggregator.MinElevation) < Consts.TOLERANCE_HEIGHT, "Invalid value for MinElevation.");
            Assert.True(Math.Abs(aggregator.MaxElevation - MAX_ELEVATION) < Consts.TOLERANCE_HEIGHT, "Invalid value for MaxElevation.");
        }
Пример #6
0
        /// <summary>
        /// Populate result grid from processed subgrid
        /// </summary>
        /// <param name="subGrid"></param>
        private void ExtractRequiredValues(ClientHeightLeafSubGrid subGrid)
        {
            var   worldExtents        = subGrid.WorldExtents();
            var   subGridWorldOriginY = worldExtents.MinY;
            var   subGridWorldOriginX = worldExtents.MinX;
            var   topX = worldExtents.MaxX;
            var   topY = worldExtents.MaxY;
            float elev;

            // Work out the x/y range across our grid we will lookup values
            double rangeMinX = (subGridWorldOriginX - TileMinX) / GridIntervalX;
            var    posX      = (int)(Math.Truncate(rangeMinX));

            TileRangeMinX = (posX == (int)rangeMinX) ? (int)rangeMinX : posX + 1;
            if (TileRangeMinX < 0)
            {
                TileRangeMinX = 0;
            }

            double rangeMinY = (subGridWorldOriginY - TileMinY) / GridIntervalY;
            var    posY      = (int)(Math.Truncate(rangeMinY));

            TileRangeMinY = (posY == (int)rangeMinY) ? (int)rangeMinY : posY + 1;
            if (TileRangeMinY < 0)
            {
                TileRangeMinY = 0;
            }

            double rangeMaxX = (topX - TileMinX) / GridIntervalX;

            TileRangeMaxX = (int)(Math.Truncate(rangeMaxX));
            if (TileRangeMaxX > GridSize - 1)
            {
                TileRangeMaxX = GridSize - 1;
            }

            double rangeMaxY = (topY - TileMinY) / GridIntervalY;

            TileRangeMaxY = (int)(Math.Truncate(rangeMaxY));
            if (TileRangeMaxY > GridSize - 1)
            {
                TileRangeMaxY = GridSize - 1;
            }

            // Iterate over our grid and extract cell heights from subgrid
            for (int y = TileRangeMinY; y <= TileRangeMaxY; y++)
            {
                for (int x = TileRangeMinX; x <= TileRangeMaxX; x++)
                {
                    // based on grid position lookup cell value
                    // use grid's easting northing value to find subgrid cell we are interested in
                    SubGridTree.CalculateIndexOfCellContainingPosition(GriddedElevDataArray[x, y].Easting, GriddedElevDataArray[x, y].Northing,
                                                                       subGrid.CellSize,
                                                                       subGrid.IndexOriginOffset,
                                                                       out int CellX, out int CellY);
                    subGrid.GetOTGLeafSubGridCellIndex(CellX, CellY, out var subGridX, out var subGridY);
                    // if we have a valid height add it to our data grid
                    if (subGrid.Cells[subGridX, subGridY] != CellPassConsts.NullHeight)
                    {
                        elev = subGrid.Cells[subGridX, subGridY];
                        GriddedElevDataArray[x, y].Elevation = elev;
                        if (elev < MinElevation)
                        {
                            MinElevation = elev;
                        }
                        if (elev > MaxElevation)
                        {
                            MaxElevation = elev;
                        }
                    }
                }
            }
        }
Пример #7
0
        protected void ProcessVolumeInformationForSubGrid(ClientHeightLeafSubGrid baseScanSubGrid,
                                                          ClientHeightLeafSubGrid topScanSubGrid)
        {
            _log.LogDebug("In ProcessVolumeInformationForSubGrid");

            try
            {
                // DesignHeights represents all the valid spot elevations for the cells in the
                // sub grid being processed
                (IClientHeightLeafSubGrid designHeights, DesignProfilerRequestResult profilerRequestResult)getDesignHeightsResult = (null, DesignProfilerRequestResult.UnknownError);

                // FCellArea is a handy place to store the cell area, rather than calculate it all the time (value wont change);
                var cellArea = CellSize * CellSize;

                // Query the patch of elevations from the surface model for this sub grid
                if (ActiveDesign?.Design != null)
                {
                    _log.LogDebug("About to call ActiveDesign.Design.GetDesignHeightsViaLocalCompute()");

                    getDesignHeightsResult = ActiveDesign.Design.GetDesignHeightsViaLocalCompute(SiteModel, ActiveDesign.Offset, baseScanSubGrid.OriginAsCellAddress(), CellSize);

                    if (getDesignHeightsResult.profilerRequestResult != DesignProfilerRequestResult.OK &&
                        getDesignHeightsResult.profilerRequestResult != DesignProfilerRequestResult.NoElevationsInRequestedPatch)
                    {
                        _log.LogError($"Design profiler sub grid elevation request for {baseScanSubGrid.OriginAsCellAddress()} failed with error {getDesignHeightsResult.profilerRequestResult}");
                        return;
                    }
                }

                var bits = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled);

                // ReSharper disable once CompareOfFloatsByEqualityOperator
                var standardVolumeProcessing = LiftParams.TargetLiftThickness == Consts.NullHeight || LiftParams.TargetLiftThickness <= 0;

                var localCellsScanned   = 0;
                var localCellsUsed      = 0;
                var localCellsDiscarded = 0;
                var localCellsUsedCut   = 0;
                var localCellsUsedFill  = 0;
                var localVolume         = 0.0d;
                var localCutFillVolume  = new CutFillVolume(0, 0);

                // If we are interested in standard volume processing use this cycle
                if (standardVolumeProcessing)
                {
                    localCellsScanned += SubGridTreeConsts.SubGridTreeCellsPerSubGrid;

                    for (var i = 0; i < SubGridTreeConsts.SubGridTreeDimension; i++)
                    {
                        for (var j = 0; j < SubGridTreeConsts.SubGridTreeDimension; j++)
                        {
                            float topZ;
                            var   baseZ = baseScanSubGrid.Cells[i, j];

                            // If the user has configured a first pass thickness, then we need to subtract this height
                            // difference from the BaseZ retrieved from the current cell if this measured height was
                            // the first pass made in the cell.
                            if (LiftParams.FirstPassThickness > 0)
                            {
                                baseZ -= LiftParams.FirstPassThickness;
                            }

                            if (VolumeType == VolumeComputationType.BetweenFilterAndDesign ||
                                VolumeType == VolumeComputationType.BetweenDesignAndFilter)
                            {
                                topZ = getDesignHeightsResult.designHeights?.Cells[i, j] ?? Consts.NullHeight;

                                if (VolumeType == VolumeComputationType.BetweenDesignAndFilter)
                                {
                                    MinMax.Swap(ref baseZ, ref topZ);
                                }
                            }
                            else
                            {
                                topZ = topScanSubGrid.Cells[i, j];
                            }

                            switch (VolumeType)
                            {
                            case VolumeComputationType.None:
                                break;

                            case VolumeComputationType.AboveLevel:
                            {
                                // ReSharper disable once CompareOfFloatsByEqualityOperator
                                if (baseZ != Consts.NullHeight)
                                {
                                    localCellsUsed++;
                                    if (baseZ > BaseLevel)
                                    {
                                        localVolume += cellArea * (baseZ - BaseLevel);
                                    }
                                }
                                else
                                {
                                    localCellsDiscarded++;
                                }

                                break;
                            }

                            case VolumeComputationType.Between2Levels:
                            {
                                // ReSharper disable once CompareOfFloatsByEqualityOperator
                                if (baseZ != Consts.NullHeight)
                                {
                                    localCellsUsed++;

                                    if (baseZ > BaseLevel)
                                    {
                                        localVolume += cellArea * (baseZ < TopLevel ? (baseZ - BaseLevel) : (TopLevel - BaseLevel));
                                    }
                                }
                                else
                                {
                                    localCellsDiscarded++;
                                }

                                break;
                            }

                            case VolumeComputationType.AboveFilter:
                            case VolumeComputationType.Between2Filters:
                            case VolumeComputationType.BetweenFilterAndDesign:
                            case VolumeComputationType.BetweenDesignAndFilter:
                            {
                                // ReSharper disable once CompareOfFloatsByEqualityOperator
                                if (baseZ != Consts.NullHeight &&
                                    // ReSharper disable once CompareOfFloatsByEqualityOperator
                                    topZ != Consts.NullHeight)
                                {
                                    localCellsUsed++;

                                    //  Note the fact we have processed this cell in the coverage map
                                    bits.SetBit(i, j);

                                    var cellUsedInVolumeCalc = (topZ - baseZ >= FillTolerance) || (baseZ - topZ >= CutTolerance);

                                    // Accumulate volumes
                                    if (cellUsedInVolumeCalc)
                                    {
                                        var volumeDifference = cellArea * (topZ - baseZ);

                                        // Accumulate the 'surplus' volume. Ie: the simple summation of
                                        // all cuts and fills.
                                        localVolume += volumeDifference;

                                        // Accumulate the cuts and fills into discrete cut and fill quantities
                                        if (topZ < baseZ)
                                        {
                                            localCellsUsedCut++;
                                            localCutFillVolume.AddCutVolume(Math.Abs(volumeDifference));
                                        }
                                        else
                                        {
                                            localCellsUsedFill++;
                                            localCutFillVolume.AddFillVolume(Math.Abs(volumeDifference));
                                        }
                                    }
                                    else
                                    {
                                        // Note the fact there was no volume change in this cell
                                        // NoChangeMap.Cells[BaseScanSubGrid.OriginX + I, BaseScanSubGrid.OriginY + J] := True;
                                    }
                                }
                                else
                                {
                                    localCellsDiscarded++;
                                }
                            }
                            break;

                            default:
                                _log.LogError($"Unknown volume type {VolumeType} in ProcessVolumeInformationForSubGrid()");
                                break;
                            }
                        }
                    }
                }

                // ReSharper disable once CompareOfFloatsByEqualityOperator
                var targetLiftThicknessCalculationsRequired = LiftParams.TargetLiftThickness != Consts.NullHeight && LiftParams.TargetLiftThickness > 0;

                //If we are interested in thickness calculations do them
                if (targetLiftThicknessCalculationsRequired)
                {
                    var belowToleranceToCheck = LiftParams.TargetLiftThickness - LiftParams.BelowToleranceLiftThickness;
                    var aboveToleranceToCheck = LiftParams.TargetLiftThickness + LiftParams.AboveToleranceLiftThickness;

                    SubGridUtilities.SubGridDimensionalIterator((i, j) =>
                    {
                        var baseZ = baseScanSubGrid.Cells[i, j];
                        var topZ  = topScanSubGrid.Cells[i, j];

                        // ReSharper disable once CompareOfFloatsByEqualityOperator
                        if (baseZ != Consts.NullHeight ||
                            // ReSharper disable once CompareOfFloatsByEqualityOperator
                            topZ != Consts.NullHeight)
                        {
                            localCellsScanned++;
                        }

                        //Test if we don't have NULL values and carry on
                        // ReSharper disable once CompareOfFloatsByEqualityOperator
                        if (baseZ != Consts.NullHeight &&
                            // ReSharper disable once CompareOfFloatsByEqualityOperator
                            topZ != Consts.NullHeight)
                        {
                            bits.SetBit(i, j);
                            double elevationDiff = topZ - baseZ;

                            if (elevationDiff <= aboveToleranceToCheck && elevationDiff >= belowToleranceToCheck)
                            {
                                localCellsUsed++;
                            }
                            else if (elevationDiff > aboveToleranceToCheck)
                            {
                                localCellsUsedFill++;
                            }
                            else if (elevationDiff < belowToleranceToCheck)
                            {
                                localCellsUsedCut++;
                            }
                        }
                        else
                        {
                            localCellsDiscarded++;
                        }
                    });
                }

                // Update the quantities in the aggregator proper
                // Note: the lock is not asynchronous as this will be highly non-contended
                _lock.Wait();
                try
                {
                    CellsScanned   += localCellsScanned;
                    CellsUsed      += localCellsUsed;
                    CellsDiscarded += localCellsDiscarded;
                    CellsUsedCut   += localCellsUsedCut;
                    CellsUsedFill  += localCellsUsedFill;
                    Volume         += localVolume;
                    CutFillVolume.AddCutFillVolume(localCutFillVolume.CutVolume, localCutFillVolume.FillVolume);

                    // Record the bits for this sub grid in the coverage map by requesting the whole sub grid
                    // of bits from the leaf level and setting it in one operation under an exclusive lock
                    if (!bits.IsEmpty())
                    {
                        var coverageMapSubGrid = CoverageMap.ConstructPathToCell(baseScanSubGrid.OriginX, baseScanSubGrid.OriginY, SubGridPathConstructionType.CreateLeaf);
                        ((SubGridTreeLeafBitmapSubGrid)coverageMapSubGrid).Bits = bits;
                    }
                }
                finally
                {
                    _lock.Release();
                }
            }
            catch (Exception e)
            {
                _log.LogError(e, "Exception thrown by ProcessVolumeInformationForSubGrid - rethrowing");
                throw;
            }
            finally
            {
                _log.LogDebug("Out ProcessVolumeInformationForSubGrid");
            }
        }
Пример #8
0
        /// <summary>
        /// Performs the donkey work of the elevation patch calculation
        /// </summary>
        private IClientHeightLeafSubGrid Calc(ISiteModelBase siteModel, DesignOffset referenceDesign, double cellSize, int originX, int originY,
                                              out DesignProfilerRequestResult calcResult)
        {
            calcResult = DesignProfilerRequestResult.UnknownError;

            if (_isTraceLoggingEnabled)
            {
                _log.LogTrace("About to lock design");
            }

            var design = Designs.Lock(referenceDesign.DesignID, siteModel, cellSize, out var lockResult);

            if (design == null)
            {
                _log.LogWarning($"Failed to read design file for design {referenceDesign.DesignID}");

                calcResult = lockResult == DesignLoadResult.DesignDoesNotExist
                ? DesignProfilerRequestResult.DesignDoesNotExist
                : DesignProfilerRequestResult.FailedToLoadDesignFile;

                return(null);
            }

            try
            {
                if (_isTraceLoggingEnabled)
                {
                    _log.LogTrace("Computing sub grid elevation patch");
                }

                // Check to see if this sub grid has any design surface underlying it
                // from which to calculate an elevation patch. If not, don't bother...
                if (!design.HasElevationDataForSubGridPatch(originX >> SubGridTreeConsts.SubGridIndexBitsPerLevel,
                                                            originY >> SubGridTreeConsts.SubGridIndexBitsPerLevel))
                {
                    calcResult = DesignProfilerRequestResult.NoElevationsInRequestedPatch;
                    return(null);
                }

                var result = new ClientHeightLeafSubGrid(null, null, SubGridTreeConsts.SubGridTreeLevels, cellSize, SubGridTreeConsts.DefaultIndexOriginOffset);

                result.SetAbsoluteOriginPosition(originX & ~SubGridTreeConsts.SubGridLocalKeyMask,
                                                 originY & ~SubGridTreeConsts.SubGridLocalKeyMask);
                result.CalculateWorldOrigin(out var worldOriginX, out var worldOriginY);

                calcResult = design.InterpolateHeights(result.Cells, worldOriginX, worldOriginY, cellSize, referenceDesign.Offset)
                  ? DesignProfilerRequestResult.OK
                  : DesignProfilerRequestResult.NoElevationsInRequestedPatch;

                if (_isTraceLoggingEnabled)
                {
                    _log.LogTrace("Computed sub grid elevation patch");
                }

                return(result);
            }
            finally
            {
                if (_isTraceLoggingEnabled)
                {
                    _log.LogTrace("Unlocking design");
                }

                Designs.UnLock(referenceDesign.DesignID, design);

                if (_isTraceLoggingEnabled)
                {
                    _log.LogTrace("Completed calculating design elevations");
                }
            }
        }