Example #1
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");
            }
        }