/// <summary> /// Since the profile line will be drawn between line segment mid points we need to interpolate the cell edge points to lie on these line segments. /// </summary> /// <param name="profileResult">The profile containing the list of line segment points, both edges and mid points, for each profile type.</param> /// <param name="calcType">The type of summary volumes calculation</param> public void InterpolateEdges(CompactionProfileResult <CompactionProfileDataResult> profileResult, VolumeCalcType?calcType) { log.LogDebug("Interpolating edges"); foreach (var result in profileResult.results) { log.LogDebug($"Interpolating edges for {result.type}"); if (result.data.Count >= 3) { //First and last points are not gaps or edges. They're always the start and end of the profile line. for (int i = 1; i < result.data.Count - 1; i++) { if (result.data[i].cellType == ProfileCellType.MidPoint) { continue; } //No y to interpolate for summary volumes design-ground if (result.type != CompactionDataPoint.SUMMARY_VOLUMES || calcType != VolumeCalcType.DesignToGround) { InterpolatePoint(i, result.data, result.type, false); } //y2 to interpolate for only summary volumes ground-ground and design-ground if (result.type == CompactionDataPoint.SUMMARY_VOLUMES && calcType != VolumeCalcType.GroundToDesign) { InterpolatePoint(i, result.data, result.type, true); } } } log.LogDebug($"After interpolation for {result.type}"); } }
/// <summary> /// Adds slicer end points to the profile results if not already present /// </summary> /// <param name="profile">The profile result to check</param> public void AddSlicerEndPoints(CompactionProfileResult <CompactionDesignProfileResult> profile) { //Raptor returns only the vertices on the design surface. //Add slicer end points with NaN elevation if not present for a profile. if (profile.gridDistanceBetweenProfilePoints > 0) { foreach (var result in profile.results) { if (result.data.Count > 0) { if (result.data[0].station > 0) { result.data.Insert(0, new CompactionProfileVertex { cellType = ProfileCellType.Gap, station = 0, elevation = float.NaN }); } if (Math.Abs(result.data[result.data.Count - 1].station - profile.gridDistanceBetweenProfilePoints) > ProfilesHelper.ONE_MM) { //The start of the gap between the last point and the slicer end point is the end of the actual data. result.data[result.data.Count - 1].cellType = ProfileCellType.Gap; //Now add the slicer end point. result.data.Add(new CompactionProfileVertex { cellType = ProfileCellType.Gap, station = profile.gridDistanceBetweenProfilePoints, elevation = float.NaN }); } } } } }
/// <summary> /// Convert from one summary volumes profile representation to another. /// </summary> /// <param name="slicerProfileResult">The profile result to convert from</param> /// <param name="calcType">The type of summary volumes profile</param> /// <returns>The new profile result representation</returns> public CompactionProfileDataResult RearrangeProfileResult( CompactionProfileResult <CompactionSummaryVolumesProfileCell> slicerProfileResult, VolumeCalcType?calcType) { log.LogDebug("ConvertProfileResult: Summary volumes profile"); if (slicerProfileResult == null) { return(null); } return(new CompactionProfileDataResult { type = CompactionDataPoint.SUMMARY_VOLUMES, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.SUMMARY_VOLUMES, cellType = p.cellType, x = p.station, //y or y2 will be set later using the summary volumes design y = calcType == VolumeCalcType.DesignToGround ? float.NaN : p.lastPassHeight1, value = -p.cutFill, y2 = calcType == VolumeCalcType.GroundToDesign ? float.NaN : p.lastPassHeight2 }).ToList() }); }
/// <summary> /// Convert from one design profile representation to another /// </summary> /// <param name="slicerProfileResults">The profile result to convert from</param> /// <returns>The new profile result representation</returns> public CompactionProfileResult <CompactionDesignProfileResult> ConvertProfileResult( Dictionary <Guid, CompactionProfileResult <CompactionProfileVertex> > slicerProfileResults) { log.LogDebug("ConvertProfileResult: Design profiles"); //shouldn't ever happen but for safety check arg if (slicerProfileResults == null || slicerProfileResults.Count == 0) { throw new ServiceException(HttpStatusCode.InternalServerError, new ContractExecutionResult(ContractExecutionStatesEnum.InternalProcessingError, "Unexpected missing design profile results")); } //all gridDistanceBetweenProfilePoints are the same if the profile slices the design surface var profileWithDistance = slicerProfileResults.Values.Where(v => v.gridDistanceBetweenProfilePoints > 0) .FirstOrDefault(); var distance = profileWithDistance?.gridDistanceBetweenProfilePoints ?? 0; var profile = new CompactionProfileResult <CompactionDesignProfileResult> { gridDistanceBetweenProfilePoints = distance, results = (from spr in slicerProfileResults select new CompactionDesignProfileResult { designFileUid = spr.Key, data = spr.Value.results }).ToList() }; return(profile); }
/// <summary> /// Process the profile request to get production data profiles /// </summary> /// <param name="request">Profile request</param> /// <returns>Profile for each production data type except summary volumes</returns> private async Task <CompactionProfileResult <CompactionProfileDataResult> > ProcessProductionData(CompactionProfileProductionDataRequest request) { CompactionProfileResult <CompactionProfileDataResult> totalResult; var productionDataProfileResult = #if RAPTOR UseTRexGateway("ENABLE_TREX_GATEWAY_PROFILING") ? #endif await ProcessProductionDataWithTRexGateway(request) #if RAPTOR : ProcessProductionDataWithRaptor(request) #endif ; if (productionDataProfileResult != null) { totalResult = profileResultHelper.RearrangeProfileResult(productionDataProfileResult); } else { //For convenience return empty list rather than null for easier manipulation totalResult = new CompactionProfileResult <CompactionProfileDataResult> { results = new List <CompactionProfileDataResult>() }; } return(totalResult); }
/// <summary> /// Add mid points between the cell edge intersections. This is because the profile line is plotted using these points. /// The cell edges are retained as this is where the color changes on the graph or chart. /// </summary> /// <param name="profileResult">The profile results from Raptor, one list of cell points for each profile type</param> /// <returns>The complete list of interspersed edges and mid points for each profile type.</returns> public void AddMidPoints(CompactionProfileResult <CompactionProfileDataResult> profileResult) { log.LogDebug("Adding midpoints"); foreach (var result in profileResult.results) { log.LogDebug($"Adding midpoints for {result.type}"); if (result.data.Count >= 4) { //No mid point for first and last segments since only partial across the cell. //We have already added them as mid points. var points = new List <CompactionDataPoint> { result.data[0] }; for (int i = 1; i < result.data.Count - 2; i++) { points.Add(result.data[i]); if (result.data[i].cellType != ProfileCellType.Gap) { var midPoint = new CompactionDataPoint(result.data[i]) { cellType = ProfileCellType.MidPoint, x = result.data[i].x + (result.data[i + 1].x - result.data[i].x) / 2 }; points.Add(midPoint); } } points.Add(result.data[result.data.Count - 2]); points.Add(result.data[result.data.Count - 1]); result.data = points; } StringBuilder sb = new StringBuilder(); sb.Append($"After adding midpoints for {result.type}: {result.data.Count}"); foreach (var point in result.data) { sb.Append($",{point.cellType}"); } log.LogDebug(sb.ToString()); } }
private CompactionProfileResult <CompactionProfileVertex> PerformProductionDataProfilePost(CompactionProfileDesignRequest request) { CompactionProfileResult <CompactionProfileVertex> result; try { ProfilesHelper.ConvertProfileEndPositions(request.GridPoints, request.WGS84Points, out TWGS84Point startPt, out TWGS84Point endPt, out bool positionsAreGrid); var designProfile = DesignProfiler.ComputeProfile.RPC.__Global.Construct_CalculateDesignProfile_Args( request.ProjectId ?? VelociraptorConstants.NO_PROJECT_ID, false, startPt, endPt, ValidationConstants3D.MIN_STATION, ValidationConstants3D.MAX_STATION, RaptorConverters.DesignDescriptor(request.DesignDescriptor), RaptorConverters.EmptyDesignDescriptor, RaptorConverters.ConvertFilter(request.Filter, request.ProjectId, raptorClient), positionsAreGrid); var memoryStream = raptorClient.GetDesignProfile(designProfile); if (memoryStream != null) { result = ConvertProfileResult(memoryStream); memoryStream.Close(); } else { //For convenience return empty list rather than null for easier manipulation result = new CompactionProfileResult <CompactionProfileVertex> { results = new List <CompactionProfileVertex>() }; } } finally { ContractExecutionStates.ClearDynamic(); } return(result); }
private CompactionProfileResult <CompactionProfileVertex> ConvertTRexProfileResult(DesignProfileResult profile) { log.LogDebug("Converting TRex profile result"); var profileResult = new CompactionProfileResult <CompactionProfileVertex>(); profileResult.results = profile.HasData() ? profile.ProfileLine.ConvertAll(dpv => new CompactionProfileVertex { cellType = dpv.Z >= VelociraptorConstants.NO_HEIGHT ? ProfileCellType.Gap : ProfileCellType.Edge, elevation = dpv.Z >= VelociraptorConstants.NO_HEIGHT ? float.NaN : (float)dpv.Z, station = dpv.Station }) : new List <CompactionProfileVertex>(); profileResult.gridDistanceBetweenProfilePoints = profile.ProfileLine.Count > 1 ? profile.ProfileLine[profile.ProfileLine.Count - 1].Station - profile.ProfileLine[0].Station : 0; FixGaps(profileResult.results); return(profileResult); }
private CompactionProfileResult <CompactionProfileVertex> ConvertProfileResult(MemoryStream ms) { log.LogDebug("Converting profile result"); var profileResult = new CompactionProfileResult <CompactionProfileVertex>(); var pdsiProfile = new DesignProfile(); pdsiProfile.ReadFromStream(ms); profileResult.results = pdsiProfile.vertices.ConvertAll(dpv => new CompactionProfileVertex { cellType = dpv.elevation >= VelociraptorConstants.NO_HEIGHT ? ProfileCellType.Gap : ProfileCellType.Edge, elevation = dpv.elevation >= VelociraptorConstants.NO_HEIGHT ? float.NaN : dpv.elevation, station = dpv.station }); profileResult.gridDistanceBetweenProfilePoints = pdsiProfile.GridDistanceBetweenProfilePoints; FixGaps(profileResult.results); return(profileResult); }
/// <summary> /// Process profile request to get summary volumes profile /// </summary> /// <param name="request">Profile request</param> /// <param name="totalResult">Results for other production data profile types</param> /// <returns>Summary volumes profile</returns> private async Task <CompactionProfileDataResult> ProcessSummaryVolumes(CompactionProfileProductionDataRequest request, CompactionProfileResult <CompactionProfileDataResult> totalResult) { var volumesResult = #if RAPTOR UseTRexGateway("ENABLE_TREX_GATEWAY_PROFILING") ? #endif await ProcessSummaryVolumesWithTRexGateway(request) #if RAPTOR : ProcessSummaryVolumesWithRaptor(request) #endif ; //If we have no other profile results apart from summary volumes, set the total grid distance if (totalResult.results.Count == 0 && volumesResult != null) { totalResult.gridDistanceBetweenProfilePoints = volumesResult.gridDistanceBetweenProfilePoints; } //If we have other profile types but no summary volumes, add summary volumes with just slicer end points if (volumesResult == null && totalResult.results.Count > 0) { var startSlicer = new CompactionSummaryVolumesProfileCell(SumVolGapCell); var endSlicer = new CompactionSummaryVolumesProfileCell(SumVolGapCell); endSlicer.station = totalResult.gridDistanceBetweenProfilePoints; volumesResult = new CompactionProfileResult <CompactionSummaryVolumesProfileCell> { gridDistanceBetweenProfilePoints = totalResult.gridDistanceBetweenProfilePoints, results = new List <CompactionSummaryVolumesProfileCell> { startSlicer, endSlicer } }; } return(profileResultHelper.RearrangeProfileResult(volumesResult, request.VolumeCalcType)); }
/// <summary> /// Calculate the elevations for cut-fill or summary volumes cells from the design surface. /// </summary> /// <param name="projectId">Legacy project ID</param> /// <param name="ProjectUid">Project's unique identifier</param> /// <param name="settings">Project settings</param> /// <param name="startLatDegrees">The start latitude of the slicer line in decimal degrees</param> /// <param name="startLonDegrees">The start longitude of the slicer line in decimal degrees</param> /// <param name="endLatDegrees">The end latitude of the slicer line in decimal degrees</param> /// <param name="endLonDegrees">The end longitude of the slicer line in decimal degrees</param> /// <param name="design">The design surface descriptor</param> /// <param name="profileResultHelper">Utility class to do the work</param> /// <param name="slicerProductionDataResult">The slicer profile results containing the production data profiles</param> /// <param name="type">The type of profile, either cut-fill or summary volumes</param> /// <param name="volumeCalcType">Summary volumes calculation type</param> private async Task FindCutFillElevations( long projectId, Guid ProjectUid, CompactionProjectSettings settings, double startLatDegrees, double startLonDegrees, double endLatDegrees, double endLonDegrees, DesignDescriptor design, ICompactionProfileResultHelper profileResultHelper, CompactionProfileResult <CompactionProfileDataResult> slicerProductionDataResult, string type, VolumeCalcType volumeCalcType) { //Get design profile var slicerDesignProfileRequest = requestFactory.Create <DesignProfileRequestHelper>(r => r .ProjectId(projectId) .ProjectUid(ProjectUid) .Headers(this.CustomHeaders) .ProjectSettings(settings) .DesignDescriptor(design)) .CreateDesignProfileRequest(startLatDegrees, startLonDegrees, endLatDegrees, endLonDegrees); slicerDesignProfileRequest.Validate(); var slicerDesignResult = await WithServiceExceptionTryExecuteAsync(() => RequestExecutorContainerFactory .Build <CompactionDesignProfileExecutor>(LoggerFactory, #if RAPTOR RaptorClient, #endif configStore : ConfigStore, trexCompactionDataProxy : TRexCompactionDataProxy, customHeaders : CustomHeaders, userId : GetUserId(), fileImportProxy : FileImportProxy) .ProcessAsync(slicerDesignProfileRequest) ); //Find the cut-fill elevations for the cell stations from the design vertex elevations profileResultHelper.FindCutFillElevations(slicerProductionDataResult, (CompactionProfileResult <CompactionProfileVertex>)slicerDesignResult, type, volumeCalcType); }
/// <summary> /// The profiles for various types (CMV, temperature, pass count etc.) may have several points /// in sequence which have no data which are effectively a single gap. Remove these repeated /// points and just keep the start of the gap and the next data point. /// </summary> /// <param name="result">The profile result to remove the repeated gaps from</param> /// <param name="calcType">The type of summary volumes calculation</param> public void RemoveRepeatedNoData(CompactionProfileResult <CompactionProfileDataResult> result, VolumeCalcType?calcType) { log.LogDebug("RemoveRepeatedNoData: Production data profile"); bool isDesignToGround = calcType.HasValue && calcType == VolumeCalcType.DesignToGround; foreach (var profileResult in result.results) { if (profileResult.data.Count > 0) { //Identify all the gaps. All data with NaN elevation or value is effectively a gap. //The exception is a summary volumes profile that is design to ground where y is NaN as it will be set later using the design. In this case use y2. foreach (var point in profileResult.data) { bool noValue = point.type.StartsWith("passCount") ? point.value == -1 : float.IsNaN(point.value); bool noY = point.type == CompactionDataPoint.SUMMARY_VOLUMES && isDesignToGround ? point.y2.HasValue && float.IsNaN(point.y2.Value) : float.IsNaN(point.y); if (noY || noValue) { point.cellType = ProfileCellType.Gap; } } //Now remove repeated gaps. //Always keep first and last points as they are the slicer end points CompactionDataPoint prevData = profileResult.data[0]; bool haveGap = prevData.cellType == ProfileCellType.Gap; List <CompactionDataPoint> newList = new List <CompactionDataPoint> { prevData }; for (int i = 1; i < profileResult.data.Count - 1; i++) { if (profileResult.data[i].cellType == ProfileCellType.Gap) { if (!haveGap) { //This is the start of a gap - keep it haveGap = true; newList.Add(profileResult.data[i]); } //else ignore it - repeated gap } else { //A data point - keep it haveGap = false; newList.Add(profileResult.data[i]); } } newList.Add(profileResult.data[profileResult.data.Count - 1]); //If the only 2 points are the slicer end points and they have no data then //remove them and return an empty list to indicate no profile data at all. if (newList.Count == 2 && newList[0].cellType == ProfileCellType.Gap && newList[1].cellType == ProfileCellType.Gap) { newList.RemoveRange(0, 2); } profileResult.data = newList; } } }
/// <summary> /// Find the cut-fill elevations for the cells from the cut-fill design elevations /// </summary> /// <param name="slicerProfileResult">The production data profile result with the cells</param> /// <param name="slicerDesignResult">The design profile result with the vertices</param> /// <param name="type">The type of profile to do, either cut-fill or summary volumes</param> /// <param name="calcType">The type of summary volumes calculation</param> public void FindCutFillElevations(CompactionProfileResult <CompactionProfileDataResult> slicerProfileResult, CompactionProfileResult <CompactionProfileVertex> slicerDesignResult, string type, VolumeCalcType calcType) { log.LogDebug($"FindCutFillElevations: {type}"); if (type != CompactionDataPoint.CUT_FILL && type != CompactionDataPoint.SUMMARY_VOLUMES) { return; } if (calcType == VolumeCalcType.GroundToGround) { return; } var vertices = slicerDesignResult.results; var cells = (from r in slicerProfileResult.results where r.type == type select r).Single().data; if (cells != null && cells.Count > 0 && vertices != null && vertices.Count > 0) { int startIndx = -1; foreach (var cell in cells) { startIndx = FindVertexIndex(vertices, cell.x, startIndx); if (startIndx != -1) { float newy = float.NaN; //Check for no design elevation if (float.IsNaN(vertices[startIndx].elevation) || float.IsNaN(vertices[startIndx + 1].elevation)) { //If the cell station matches (within 3mm) either vertex station //then we can use that vertex elevation directly const double THREE_MM = 0.003; if (Math.Abs(vertices[startIndx].station - cell.x) <= THREE_MM) { newy = vertices[startIndx].elevation; } else if (Math.Abs(vertices[startIndx + 1].station - cell.x) <= THREE_MM) { newy = vertices[startIndx + 1].elevation; } } else { //Calculate elevation by interpolation var proportion = (cell.x - vertices[startIndx].station) / (vertices[startIndx + 1].station - vertices[startIndx].station); newy = (float)(vertices[startIndx].elevation + proportion * (vertices[startIndx + 1].elevation - vertices[startIndx].elevation)); } if (calcType == VolumeCalcType.DesignToGround) { cell.y = newy; } else { cell.y2 = newy; } } } } }
/// <summary> /// Convert from one production data profile representation to another. The source is a list with each item containing the /// data for every profile type. The destination is a list of lists, one list for each profile type containing its own data. /// </summary> /// <param name="slicerProfileResult">The profile result to convert from</param> /// <returns>The new profile result representation</returns> public CompactionProfileResult <CompactionProfileDataResult> RearrangeProfileResult( CompactionProfileResult <CompactionProfileCell> slicerProfileResult) { log.LogDebug("ConvertProfileResult: Production data profile"); //shouldn't ever happen but for safety check arg if (slicerProfileResult?.results == null) { throw new ServiceException(HttpStatusCode.InternalServerError, new ContractExecutionResult(ContractExecutionStatesEnum.InternalProcessingError, "Unexpected missing profile result")); } var profile = new CompactionProfileResult <CompactionProfileDataResult> { gridDistanceBetweenProfilePoints = slicerProfileResult.gridDistanceBetweenProfilePoints, results = new List <CompactionProfileDataResult> { new CompactionProfileDataResult { type = CompactionDataPoint.FIRST_PASS, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.FIRST_PASS, cellType = p.cellType, x = p.station, y = p.firstPassHeight, value = p.firstPassHeight }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.HIGHEST_PASS, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.HIGHEST_PASS, cellType = p.cellType, x = p.station, y = p.highestPassHeight, value = p.highestPassHeight }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.LAST_PASS, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.LAST_PASS, cellType = p.cellType, x = p.station, y = p.lastPassHeight, value = p.lastPassHeight }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.LOWEST_PASS, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.LOWEST_PASS, cellType = p.cellType, x = p.station, y = p.lowestPassHeight, value = p.lowestPassHeight }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.LAST_COMPOSITE, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.LAST_COMPOSITE, cellType = p.cellType, x = p.station, y = p.lastCompositeHeight, value = p.lastCompositeHeight }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.CMV_SUMMARY, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.CMV_SUMMARY, cellType = p.cellType, x = p.station, y = p.cmvHeight, value = p.cmvPercent, valueType = p.cmvIndex }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.CMV_DETAIL, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.CMV_DETAIL, cellType = p.cellType, x = p.station, y = p.cmvHeight, value = p.cmv }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.CMV_PERCENT_CHANGE, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.CMV_PERCENT_CHANGE, cellType = p.cellType, x = p.station, y = p.cmvHeight, value = p.cmvPercentChange }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.MDP_SUMMARY, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.MDP_SUMMARY, cellType = p.cellType, x = p.station, y = p.mdpHeight, value = p.mdpPercent, valueType = p.mdpIndex }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.TEMPERATURE_SUMMARY, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.TEMPERATURE_SUMMARY, cellType = p.cellType, x = p.station, y = p.temperatureHeight, value = p.temperature, valueType = p.temperatureIndex }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.TEMPERATURE_DETAIL, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.TEMPERATURE_DETAIL, cellType = p.cellType, x = p.station, y = p.temperatureHeight, value = p.temperature }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.SPEED_SUMMARY, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.SPEED_SUMMARY, cellType = p.cellType, x = p.station, y = p.lastPassHeight, value = p.minSpeed, value2 = p.maxSpeed, valueType = p.speedIndex }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.PASS_COUNT_SUMMARY, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.PASS_COUNT_SUMMARY, cellType = p.cellType, x = p.station, y = p.lastPassHeight, value = p.topLayerPassCount, valueType = p.passCountIndex }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.PASS_COUNT_DETAIL, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.PASS_COUNT_DETAIL, cellType = p.cellType, x = p.station, y = p.lastPassHeight, value = p.topLayerPassCount }).ToList() }, new CompactionProfileDataResult { type = CompactionDataPoint.CUT_FILL, data = (from p in slicerProfileResult.results select new CompactionDataPoint { type = CompactionDataPoint.CUT_FILL, cellType = p.cellType, x = p.station, y = p.lastCompositeHeight, value = p.cutFill, y2 = float.NaN, //will be set later using the cut-fill design }).ToList() } } }; return(profile); }
private CompactionProfileResult <CompactionSummaryVolumesProfileCell> ProcessSummaryVolumesProfileCells(List <SummaryVolumeProfileCell> profileCells, double gridDistanceBetweenProfilePoints, VolumeCalcType calcType) { var profile = new CompactionProfileResult <CompactionSummaryVolumesProfileCell>(); profile.results = new List <CompactionSummaryVolumesProfileCell>(); SummaryVolumeProfileCell prevCell = null; foreach (var currCell in profileCells) { var gapExists = ProfilesHelper.CellGapExists(prevCell, currCell, out var prevStationIntercept); if (gapExists) { var gapCell = new CompactionSummaryVolumesProfileCell(SumVolGapCell); gapCell.station = prevStationIntercept; profile.results.Add(gapCell); } var lastPassHeight1 = currCell.LastCellPassElevation1 == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.LastCellPassElevation1; var lastPassHeight2 = currCell.LastCellPassElevation2 == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.LastCellPassElevation2; var designHeight = currCell.DesignElev == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.DesignElev; float cutFill = float.NaN; switch (calcType) { case VolumeCalcType.GroundToGround: cutFill = float.IsNaN(lastPassHeight1) || float.IsNaN(lastPassHeight2) ? float.NaN : lastPassHeight2 - lastPassHeight1; break; case VolumeCalcType.GroundToDesign: cutFill = float.IsNaN(lastPassHeight1) || float.IsNaN(designHeight) ? float.NaN : designHeight - lastPassHeight1; break; case VolumeCalcType.DesignToGround: cutFill = float.IsNaN(designHeight) || float.IsNaN(lastPassHeight2) ? float.NaN : lastPassHeight2 - designHeight; break; } profile.results.Add(new CompactionSummaryVolumesProfileCell { cellType = prevCell == null ? ProfileCellType.MidPoint : ProfileCellType.Edge, station = currCell.Station, lastPassHeight1 = lastPassHeight1, lastPassHeight2 = lastPassHeight2, designHeight = designHeight, cutFill = cutFill }); prevCell = currCell; } //Add a last point at the intercept length of the last cell so profiles are drawn correctly if (prevCell != null && prevCell.InterceptLength > ProfilesHelper.ONE_MM) { var lastCell = new CompactionSummaryVolumesProfileCell(profile.results[profile.results.Count - 1]) { station = prevCell.Station + prevCell.InterceptLength }; profile.results.Add(lastCell); } if (profile.results.Count > 0) { profile.results[profile.results.Count - 1].cellType = ProfileCellType.MidPoint; } profile.gridDistanceBetweenProfilePoints = gridDistanceBetweenProfilePoints; var sb = new StringBuilder(); sb.Append($"After summary volumes profile conversion: {profile.results.Count}"); foreach (var cell in profile.results) { sb.Append($",{cell.cellType}"); } log.LogDebug(sb.ToString()); return(profile); }
private CompactionProfileResult <CompactionProfileCell> ProcessProductionDataProfileCells(List <ProfileCellData> profileCells, double gridDistanceBetweenProfilePoints, LiftBuildSettings liftBuildSettings) { var profile = new CompactionProfileResult <CompactionProfileCell>(); profile.results = new List <CompactionProfileCell>(); ProfileCellData prevCell = null; foreach (var currCell in profileCells) { var gapExists = ProfilesHelper.CellGapExists(prevCell, currCell, out double prevStationIntercept); if (gapExists) { var gapCell = new CompactionProfileCell(GapCell); gapCell.station = prevStationIntercept; profile.results.Add(gapCell); } var lastPassHeight = currCell.LastPassHeight == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.LastPassHeight; var lastCompositeHeight = currCell.CompositeLastPassHeight == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.CompositeLastPassHeight; var designHeight = currCell.DesignHeight == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.DesignHeight; bool noCCVValue = currCell.TargetCCV == 0 || currCell.TargetCCV == VelociraptorConstants.NO_CCV || currCell.CCV == VelociraptorConstants.NO_CCV; bool noCCVElevation = currCell.CCVElev == VelociraptorConstants.NULL_SINGLE || noCCVValue; bool noMDPValue = currCell.TargetMDP == 0 || currCell.TargetMDP == VelociraptorConstants.NO_MDP || currCell.MDP == VelociraptorConstants.NO_MDP; bool noMDPElevation = currCell.MDPElev == VelociraptorConstants.NULL_SINGLE || noMDPValue; bool noTemperatureValue = currCell.MaterialTemperature == VelociraptorConstants.NO_TEMPERATURE; bool noTemperatureElevation = currCell.MaterialTemperatureElev == VelociraptorConstants.NULL_SINGLE || noTemperatureValue; bool noPassCountValue = currCell.TopLayerPassCount == VelociraptorConstants.NO_PASSCOUNT; //Either have none or both speed values var noSpeedValue = currCell.CellMaxSpeed == VelociraptorConstants.NO_SPEED; var speedMin = noSpeedValue ? float.NaN : (float)(currCell.CellMinSpeed / ConversionConstants.KM_HR_TO_CM_SEC); var speedMax = noSpeedValue ? float.NaN : (float)(currCell.CellMaxSpeed / ConversionConstants.KM_HR_TO_CM_SEC); var cmvPercent = noCCVValue ? float.NaN : (float)currCell.CCV / (float)currCell.TargetCCV * 100.0F; var mdpPercent = noMDPValue ? float.NaN : (float)currCell.MDP / (float)currCell.TargetMDP * 100.0F; var firstPassHeight = currCell.FirstPassHeight == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.FirstPassHeight; var highestPassHeight = currCell.HighestPassHeight == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.HighestPassHeight; var lowestPassHeight = currCell.LowestPassHeight == VelociraptorConstants.NULL_SINGLE ? float.NaN : currCell.LowestPassHeight; var cutFill = float.IsNaN(lastCompositeHeight) || float.IsNaN(designHeight) ? float.NaN : lastCompositeHeight - designHeight; var cmv = noCCVValue ? float.NaN : currCell.CCV / 10.0F; var cmvHeight = noCCVElevation ? float.NaN : currCell.CCVElev; var mdpHeight = noMDPElevation ? float.NaN : currCell.MDPElev; var temperature = noTemperatureValue ? float.NaN : currCell.MaterialTemperature / 10.0F; // As temperature is reported in 10th... var temperatureHeight = noTemperatureElevation ? float.NaN : currCell.MaterialTemperatureElev; var topLayerPassCount = noPassCountValue ? -1 : currCell.TopLayerPassCount; var cmvPercentChange = currCell.CCV == VelociraptorConstants.NO_CCV ? float.NaN : (currCell.PrevCCV == VelociraptorConstants.NO_CCV ? 100.0f : (float)(currCell.CCV - currCell.PrevCCV) / (float)currCell.PrevCCV * 100.0f); var passCountIndex = noPassCountValue || float.IsNaN(lastPassHeight) ? ValueTargetType.NoData : (currCell.TopLayerPassCount < currCell.TopLayerPassCountTargetRangeMin ? ValueTargetType.BelowTarget : (currCell.TopLayerPassCount > currCell.TopLayerPassCountTargetRangeMax ? ValueTargetType.AboveTarget : ValueTargetType.OnTarget)); var temperatureIndex = noTemperatureValue || noTemperatureElevation ? ValueTargetType.NoData : (currCell.MaterialTemperature < currCell.MaterialTemperatureWarnMin ? ValueTargetType.BelowTarget : (currCell.MaterialTemperature > currCell.MaterialTemperatureWarnMax ? ValueTargetType.AboveTarget : ValueTargetType.OnTarget)); var cmvIndex = noCCVValue || noCCVElevation ? ValueTargetType.NoData : (cmvPercent < liftBuildSettings.CCVRange.Min ? ValueTargetType.BelowTarget : (cmvPercent > liftBuildSettings.CCVRange.Max ? ValueTargetType.AboveTarget : ValueTargetType.OnTarget)); var mdpIndex = noMDPValue || noMDPElevation ? ValueTargetType.NoData : (mdpPercent < liftBuildSettings.MDPRange.Min ? ValueTargetType.BelowTarget : (mdpPercent > liftBuildSettings.MDPRange.Max ? ValueTargetType.AboveTarget : ValueTargetType.OnTarget)); var speedIndex = noSpeedValue || float.IsNaN(lastPassHeight) ? ValueTargetType.NoData : (currCell.CellMaxSpeed > liftBuildSettings.MachineSpeedTarget.MaxTargetMachineSpeed ? ValueTargetType.AboveTarget : (currCell.CellMinSpeed < liftBuildSettings.MachineSpeedTarget.MinTargetMachineSpeed && currCell.CellMaxSpeed < liftBuildSettings.MachineSpeedTarget.MinTargetMachineSpeed ? ValueTargetType.BelowTarget : ValueTargetType.OnTarget)); profile.results.Add(new CompactionProfileCell { cellType = prevCell == null ? ProfileCellType.MidPoint : ProfileCellType.Edge, station = currCell.Station, firstPassHeight = firstPassHeight, highestPassHeight = highestPassHeight, lastPassHeight = lastPassHeight, lowestPassHeight = lowestPassHeight, lastCompositeHeight = lastCompositeHeight, designHeight = designHeight, cutFill = cutFill, cmv = cmv, cmvPercent = cmvPercent, cmvHeight = cmvHeight, mdpPercent = mdpPercent, mdpHeight = mdpHeight, temperature = temperature, temperatureHeight = temperatureHeight, topLayerPassCount = topLayerPassCount, cmvPercentChange = cmvPercentChange, minSpeed = speedMin, maxSpeed = speedMax, passCountIndex = passCountIndex, temperatureIndex = temperatureIndex, cmvIndex = cmvIndex, mdpIndex = mdpIndex, speedIndex = speedIndex }); prevCell = currCell; } //Add a last point at the intercept length of the last cell so profiles are drawn correctly if (prevCell != null && prevCell.InterceptLength > ProfilesHelper.ONE_MM) { var lastCell = new CompactionProfileCell(profile.results[profile.results.Count - 1]) { station = prevCell.Station + prevCell.InterceptLength }; profile.results.Add(lastCell); } if (profile.results.Count > 0) { profile.results[profile.results.Count - 1].cellType = ProfileCellType.MidPoint; } profile.gridDistanceBetweenProfilePoints = gridDistanceBetweenProfilePoints; var sb = new StringBuilder(); sb.Append($"After profile conversion: {profile.results.Count}"); foreach (var cell in profile.results) { sb.Append($",{cell.cellType}"); } log.LogDebug(sb.ToString()); return(profile); }