/// <summary> /// Merges the 'from' elevation sub grid and the 'intermediary' sub grid result into a single sub grid for /// subsequent calculation. THe result is placed into the 'from' sub grid. /// </summary> private void MergeIntermediaryResults(ClientHeightAndTimeLeafSubGrid heightGrid1, ClientHeightAndTimeLeafSubGrid intermediaryHeightGrid) { // Combine this result with the result of the first query to obtain a modified heights grid // Merge the first two results to give the profile calc the correct combined 'from' surface // HeightsGrid1 is 'latest @ first filter', HeightsGrid1 is earliest @ second filter SubGridUtilities.SubGridDimensionalIterator((x, y) => { if (heightGrid1.Cells[x, y] == CellPassConsts.NullHeight && // Check if there is a non null candidate in the earlier @ second filter intermediaryHeightGrid.Cells[x, y] != CellPassConsts.NullHeight) { heightGrid1.Cells[x, y] = intermediaryHeightGrid.Cells[x, y]; heightGrid1.Times[x, y] = intermediaryHeightGrid.Times[x, y]; } }); }
/// <summary> /// Populate requested elevation information into the sub grid result /// </summary> /// <param name="subGrid"></param> public override void Populate(IClientLeafSubGrid subGrid) { //======================================================================================== byte BytesForRangeExcludingNull(uint range) => range < byte.MaxValue ? ONE_BYTE : range < ushort.MaxValue ? TWO_BYTES : FOUR_BYTES; //======================================================================================== base.Populate(subGrid); ClientHeightAndTimeLeafSubGrid elevSubGrid = (ClientHeightAndTimeLeafSubGrid)subGrid; var elevations = elevSubGrid.Cells; var times = elevSubGrid.Times; IsNull = true; subGrid.CalculateWorldOrigin(out var worldOriginX, out var worldOriginY); SubGridOriginX = worldOriginX; SubGridOriginY = worldOriginY; if (elevSubGrid.Cells != null) { // Determine the minimum/maximum non-null elevation/time in the sub grid double minElevation = DOUBLE_VALUE; double maxElevation = -DOUBLE_VALUE; uint minTime = TIME_MAXIMUM_VALUE; uint maxTime = TIME_MINIMUM_VALUE; SubGridUtilities.SubGridDimensionalIterator((x, y) => { var valueHeight = elevations[x, y]; if (Math.Abs(valueHeight - CellPassConsts.NullHeight) > Consts.TOLERANCE_DIMENSION) { if (valueHeight < minElevation) { minElevation = valueHeight; } if (valueHeight > maxElevation) { maxElevation = valueHeight; } long valueTime = times[x, y]; if (valueTime < minTime) { minTime = (uint)valueTime; } if (valueTime > maxTime) { minTime = (uint)valueTime; } } }); if (Math.Abs(minElevation - CellPassConsts.NullHeight) >= Consts.TOLERANCE_DIMENSION) { var minElevationAsMM = (uint)Math.Floor(minElevation * ELEVATION_OFFSET_FACTOR + ELEVATION_OFFSET_TOLERANCE); var maxElevationAsMM = (uint)Math.Floor(maxElevation * ELEVATION_OFFSET_FACTOR + ELEVATION_OFFSET_TOLERANCE); // Set the appropriate values into the result Data = new PatchOffsetsRecord[SubGridTreeConsts.SubGridTreeDimension, SubGridTreeConsts.SubGridTreeDimension]; IsNull = false; ElevationOrigin = (float)minElevation; ElevationOffsetSize = BytesForRangeExcludingNull(maxElevationAsMM - minElevationAsMM); TimeOrigin = minTime; TimeOffsetSize = BytesForRangeExcludingNull(minTime - maxTime); SubGridUtilities.SubGridDimensionalIterator((x, y) => { var valueHeight = elevations[x, y]; var valueTime = (uint)times[x, y]; if (Math.Abs(valueHeight - CellPassConsts.NullHeight) < Consts.TOLERANCE_DIMENSION) { Data[x, y] = new PatchOffsetsRecord(uint.MaxValue, uint.MaxValue); } else { Data[x, y] = new PatchOffsetsRecord((uint)Math.Floor((valueHeight - minElevation) * ELEVATION_OFFSET_FACTOR + ELEVATION_OFFSET_TOLERANCE), valueTime - minTime); } }); } } }
/// <summary> /// Processes each sub grid in turn into the resulting profile. /// </summary> public void ProcessSubGroup(SubGridCellAddress address, bool prodDataAtAddress, SubGridTreeBitmapSubGridBits cellOverrideMask) { var okToProceed = false; // Execute a client grid request for each requester and create an array of the results var clientGrids = Requestors.Select(x => { x.CellOverrideMask = cellOverrideMask; // Reach into the sub grid request layer and retrieve an appropriate sub grid var requestSubGridInternalResult = x.RequestSubGridInternal(address, prodDataAtAddress, true); if (requestSubGridInternalResult.requestResult != ServerRequestResult.NoError) { Log.LogError($"Request for sub grid {address} request failed with code {requestSubGridInternalResult.requestResult}"); } return(requestSubGridInternalResult.clientGrid); }).ToArray(); // If an intermediary result was requested then merge the 'from' and intermediary sub grids now if (IntermediaryFilterRequired) { MergeIntermediaryResults(clientGrids[0] as ClientHeightAndTimeLeafSubGrid, clientGrids[1] as ClientHeightAndTimeLeafSubGrid); //... and chop out the intermediary grid clientGrids = new[] { clientGrids[0], clientGrids[2] }; } // Assign the results of the sub grid requests according to the ordering of the filter in the overall // volume type context of the request ClientHeightAndTimeLeafSubGrid heightsGrid1 = null; if (VolumeType == VolumeComputationType.BetweenFilterAndDesign || VolumeType == VolumeComputationType.Between2Filters) { heightsGrid1 = clientGrids[0] as ClientHeightAndTimeLeafSubGrid; } ClientHeightAndTimeLeafSubGrid heightsGrid2 = null; if (VolumeType == VolumeComputationType.BetweenDesignAndFilter) { heightsGrid2 = clientGrids[0] as ClientHeightAndTimeLeafSubGrid; } else if (VolumeType == VolumeComputationType.Between2Filters) { heightsGrid2 = clientGrids[1] as ClientHeightAndTimeLeafSubGrid; } IClientHeightLeafSubGrid designHeights = null; if (VolumeType == VolumeComputationType.BetweenFilterAndDesign || VolumeType == VolumeComputationType.BetweenDesignAndFilter) { if (svDesignWrapper?.Design != null) { var getDesignHeightsResult = svDesignWrapper.Design.GetDesignHeightsViaLocalCompute(SiteModel, svDesignWrapper.Offset, address, SiteModel.CellSize); if (getDesignHeightsResult.errorCode != DesignProfilerRequestResult.OK || getDesignHeightsResult.designHeights == null) { if (getDesignHeightsResult.errorCode == DesignProfilerRequestResult.NoElevationsInRequestedPatch) { Log.LogInformation("Call to RequestDesignElevationPatch failed due to no elevations in requested patch."); } else { Log.LogError($"Call to RequestDesignElevationPatch failed due to no TDesignProfilerRequestResult return code {getDesignHeightsResult.errorCode}."); } } else { designHeights = getDesignHeightsResult.designHeights; okToProceed = true; } } else { Log.LogError("Missing design reference. Call to request Summary Volumes Profile using design failed due to no reference design"); } } else { okToProceed = true; } if (okToProceed) { for (int I = 0; I < cellCounter; I++) { int cellX = profileCellList[I].OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask; int cellY = profileCellList[I].OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask; if (heightsGrid1 != null) { profileCellList[I].LastCellPassElevation1 = heightsGrid1.Cells[cellX, cellY]; } if (heightsGrid2 != null) { profileCellList[I].LastCellPassElevation2 = heightsGrid2.Cells[cellX, cellY]; } profileCellList[I].DesignElev = designHeights?.Cells[cellX, cellY] ?? CellPassConsts.NullHeight; } } }