/// <summary> /// Constructs an alignment master geometry result from supplied vertices and labels /// </summary> /// <param name="requestResult"></param> /// <param name="vertices"></param> /// <param name="labels"></param> public AlignmentDesignGeometryResponse(DesignProfilerRequestResult requestResult, double[][][] vertices, AlignmentGeometryResponseArc[] arcs, AlignmentGeometryResponseLabel[] labels) { RequestResult = requestResult; Vertices = vertices; Arcs = arcs; Labels = labels; }
/// <summary> /// Performs the donkey work of the elevation patch calculation /// </summary> /// <returns>The computed elevation of the given design at the spot location, or NullDouble if the location does not lie on the design</returns> private double Calc(ISiteModelBase siteModel, DesignOffset referenceDesign, double spotX, double spotY, out DesignProfilerRequestResult calcResult) { calcResult = DesignProfilerRequestResult.UnknownError; var design = _designs.Lock(referenceDesign.DesignID, siteModel, SubGridTreeConsts.DefaultCellSize, out var lockResult); if (design == null) { _log.LogWarning($"Failed to read design file for design {referenceDesign.DesignID}"); calcResult = DesignProfilerRequestResult.FailedToLoadDesignFile; return(Common.Consts.NullDouble); } try { var hint = -1; if (design.InterpolateHeight(ref hint, spotX, spotY, referenceDesign.Offset, out var z)) { calcResult = DesignProfilerRequestResult.OK; } else { calcResult = DesignProfilerRequestResult.NoElevationsInRequestedPatch; z = Common.Consts.NullDouble; } return(z); }
/// <summary> /// Performs the donkey work of the boundary calculation /// </summary> private List <Fence> Calc(DesignBoundaryArgument arg, out DesignProfilerRequestResult calcResult) { calcResult = DesignProfilerRequestResult.UnknownError; var siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(arg.ProjectID, false); if (siteModel == null) { calcResult = DesignProfilerRequestResult.NoSelectedSiteModel; Log.LogError($"Site model {arg.ProjectID} not found"); return(null); } var design = Designs.Lock(arg.ReferenceDesign.DesignID, siteModel, siteModel.CellSize, out var lockResult); if (design == null) { Log.LogWarning($"Failed to read file for design {arg.ReferenceDesign.DesignID}"); calcResult = DesignProfilerRequestResult.FailedToLoadDesignFile; return(null); } try { var result = design.GetBoundary(); calcResult = result != null ? DesignProfilerRequestResult.OK : DesignProfilerRequestResult.FailedToCalculateBoundary; return(result); } finally { Designs.UnLock(arg.ReferenceDesign.DesignID, design); } }
public bool DetermineBoundary(out DesignProfilerRequestResult calcResult, out Fence fence) { // Todo InterlockedIncrement64(DesignProfilerRequestStats.NumAlignmentFilterBoundariesComputed); // Walk the alignment and construct a boundary as per the SVO algorithm for road design boundary construction CalculateRoadSubsetFence(out calcResult, out fence); return(calcResult == DesignProfilerRequestResult.OK && fence.NumVertices > 2); }
public override void InternalFromBinary(IBinaryRawReader reader) { var version = VersionSerializationHelper.CheckVersionByte(reader, VERSION_NUMBER); if (version == 1) { RequestResult = (DesignProfilerRequestResult)reader.ReadByte(); } }
private void CalculateRoadSubsetFence(out DesignProfilerRequestResult calcResult, out Fence fence) // Run down the road from start to end chainage in steps the size of which is // determined by the default cross section interval, computing the // left and right offset coordinates OffsetLeft & OffsetRight meters from the centerline and add these to // the fence point list { fence = new Fence(); double SubsetStartStation = Math.Max(Alignment.StartStation, StartStation); double SubsetEndStation = Math.Min(Alignment.EndStation, EndStation); if (SubsetEndStation <= SubsetStartStation) { calcResult = DesignProfilerRequestResult.InvalidStationValues; return; } double CurrentPos = SubsetStartStation; double Interval = Math.Max(MinimumStationIntervalForSVLFilterBoundaryGeneration, Math.Min(Math.Abs(OffsetLeft), Math.Abs(OffsetRight)) / 4); var RHSProfile = new Fence(); // Calculate all the offset points while (true) { AddOffsetPoints(fence, RHSProfile, CurrentPos, false); CurrentPos = CurrentPos + Interval; if (CurrentPos >= SubsetEndStation) { AddOffsetPoints(fence, RHSProfile, SubsetEndStation, true); break; } } // Now lets smooth each size if the fence, removing all points forming the apex of corners // smaller than MinimumRoadFenceAngle degrees; if (fence.NumVertices > 2) { SmoothFenceLine(fence, 1, 1, fence.NumVertices - 1); } if (RHSProfile.NumVertices > 2) { SmoothFenceLine(RHSProfile, RHSProfile.NumVertices - 2, -1, 0); } // Now copy the RHS profile fence points over to the fence for (int I = RHSProfile.NumVertices - 1; I >= 0; I--) { fence.Points.Add(RHSProfile[I]); } calcResult = DesignProfilerRequestResult.OK; }
/// <summary> /// Performs execution business logic for this executor. /// </summary> public List <Fence> Execute(DesignBoundaryArgument arg, out DesignProfilerRequestResult calcResult) { // Perform the design boundary calculation var result = Calc(arg, out calcResult); if (result == null) { Log.LogInformation($"Unable to calculate a design boundary result for {arg}"); result = new List <Fence>(); } return(result); }
/// <summary> /// Performs execution business logic for this executor /// </summary> public List <XYZS> Execute(CalculateDesignProfileArgument args, out DesignProfilerRequestResult calcResult) { // Perform the design profile calculation var result = Calc(args, out calcResult); if (result == null) { Log.LogInformation($"Unable to calculate a design profiler result for {args}"); result = new List <XYZS>(); } return(result); }
public bool ConstructSVLCenterlineAlignmentGeometry(NFFGuidableAlignmentEntity alignment) { if ((CalcResult = Validate(alignment)) != DesignProfilerRequestResult.OK) { return(false); } // Run through the entities in the alignment and add them to the geometry for (var I = 0; I < alignment.Entities.Count; I++) { AddEntityToGeometry(alignment.Entities[I]); } MoveWorkingVerticesToVertices(); // Construct the stationing text entities along the alignment var StationIncrement = AlignmentLabelingInterval; var CurrentStation = alignment.StartStation; while (CurrentStation <= alignment.EndStation + 0.001) { alignment.ComputeXY(CurrentStation, 0, out var X1, out var Y1); alignment.ComputeXY(CurrentStation, -1, out var X2, out var Y2); GeometryUtils.RectToPolar(Y1, X1, Y2, X2, out var textOrientation, out _); // Create an instance of the response label with the lat/lon coordinate set to the Y/X grid coordinates // which will be converted later by the caller Labels.Add(new AlignmentGeometryResponseLabel(CurrentStation, X1, Y1, Math.PI / 2 - textOrientation)); if (CurrentStation + StationIncrement <= alignment.EndStation) { CurrentStation += StationIncrement; } else if (CurrentStation > alignment.EndStation - 0.001) { break; } else { CurrentStation = alignment.EndStation; } } foreach (var vertices in Vertices) { vertices.FillInStationValues(); } CalcResult = DesignProfilerRequestResult.OK; return(true); }
public bool ConstructSVLCenterlineDXFAlignment(NFFGuidableAlignmentEntity alignment, out DesignProfilerRequestResult calcResult, out MemoryStream ms) { ms = null; if ((calcResult = Validate(alignment)) != DesignProfilerRequestResult.OK) { return(false); } DXF = new DXFFile(); DXF.Layers.Add("B"); // Run through the entities in the alignment and add them to the DXF file for (var I = 0; I < alignment.Entities.Count; I++) { AddEntityToDXF(alignment.Entities[I]); } // Construct the stationing text entities along the alignment var StationIncrement = AlignmentLabelingInterval; var CurrentStation = alignment.StartStation; while (CurrentStation <= alignment.EndStation + 0.001) { alignment.ComputeXY(CurrentStation, 0, out var X1, out var Y1); alignment.ComputeXY(CurrentStation, -1, out var X2, out var Y2); GeometryUtils.RectToPolar(Y1, X1, Y2, X2, out var textOrientation, out _); DXF.Entities.Add(new DXFTextEntity("B", kAlignmentCenterLineColor, X1, Y1, Consts.NullDouble, $"{CurrentStation / UnitUtils.DistToMeters(Units):F2}", textOrientation - (Math.PI / 2), 2, "Arial", //[], //0, 0, 0)); if (CurrentStation + StationIncrement <= alignment.EndStation) { CurrentStation = CurrentStation + StationIncrement; } else if (CurrentStation > alignment.EndStation - 0.001) { break; } else { CurrentStation = alignment.EndStation; } } if (DXF.Entities.Count > 0) { ms = new MemoryStream(); using var writer = new StreamWriter(ms); DXF.SaveToFile(writer); } calcResult = DesignProfilerRequestResult.OK; return(true); }
/// <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); }
/// <summary> /// Returns a list of coordinates traced over the alignment within the station range specified. /// This coordinate list is then typically used to produce a station offset report /// </summary> public List <StationOffsetPoint> GetOffsetPointsInNEE(double crossSectionInterval, double startStation, double endStation, double[] offsets, out DesignProfilerRequestResult calcResult) { var result = new List <StationOffsetPoint>(1000); double lastX = -1, lastY = -1; var subsetStartStation = Math.Max(_data.StartStation, startStation); var subsetEndStation = Math.Min(_data.EndStation, endStation); var currentStation = subsetStartStation; void AddCoord(double x, double y, double station, double offset) { if (lastX == x && lastY == y) { return; // don't wont duplicates } result.Add(new StationOffsetPoint(station, offset, x, y)); lastX = x; lastY = y; } void AddPointAtStation(double x, double y, double station, double offset, bool rangeTestRequired) { if (rangeTestRequired) // test for end of range { if (startStation >= subsetStartStation && station <= subsetEndStation) { AddCoord(x, y, station, offset); // add station if we have it } } else { AddCoord(x, y, station, offset); } } void AddSpotPointsFromElement(NFFStationedLineworkEntity element) { while (currentStation <= element.EndStation) { foreach (var offset in offsets) { element.ComputeXY(currentStation, offset, out var ptX, out var ptY); // get x y at current position AddPointAtStation(ptX, ptY, currentStation, offset, rangeTestRequired: false); } if (currentStation + crossSectionInterval > subsetEndStation && currentStation < subsetEndStation) { currentStation = subsetEndStation; // making sure last point is picked up } else { currentStation += crossSectionInterval; } } } // Run down the centre line from start to end station and add these vertices to the point list // Pattern of coords returned will be in order of left to right e.g. -2, -1, 0 (center line) , 1 ,2 calcResult = DesignProfilerRequestResult.UnknownError; if (endStation <= startStation) { calcResult = DesignProfilerRequestResult.InvalidStationValues; return(null); } // loop through all elements and add vertices where in range foreach (var currentElement in _data.Entities) { if (currentElement.EndStation < subsetStartStation) // ignore any early elements { continue; } if (currentElement.StartStation > subsetEndStation) // are we pass end of range { break; } AddSpotPointsFromElement(currentElement); } calcResult = DesignProfilerRequestResult.OK; // Made it this far so flag OK return(result); }
/// <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"); } } }
/// <summary> /// Performs execution business logic for this executor /// </summary> public IClientHeightLeafSubGrid Execute(ISiteModelBase siteModel, DesignOffset referenceDesign, double cellSize, int originX, int originY, out DesignProfilerRequestResult calcResult) { // Perform the design elevation patch calculation try { /* Test code to force all sub grids to have 0 elevations from a design * ClientHeightLeafSubGrid test = new ClientHeightLeafSubGrid(null, null, 6, 0.34, SubGridTreeConsts.DefaultIndexOriginOffset); * test.SetToZeroHeight(); * return test; */ // Calculate the patch of elevations and return it return(Calc(siteModel, referenceDesign, cellSize, originX, originY, out calcResult)); } finally { //if Debug_PerformDPServiceRequestHighRateLogging then //Log.LogInformation($"#Out# {nameof(CalculateDesignElevationPatch)}.Execute #Result# {calcResult}"); } }
/// <summary> /// Performs the donkey work of the profile calculation /// </summary> private List <XYZS> Calc(CalculateDesignProfileArgument arg, out DesignProfilerRequestResult calcResult) { calcResult = DesignProfilerRequestResult.UnknownError; var siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(arg.ProjectID); var Design = Designs.Lock(arg.ReferenceDesign.DesignID, siteModel, arg.CellSize, out DesignLoadResult LockResult); var arg2 = new CalculateDesignProfileArgument_ClusterCompute { ProjectID = arg.ProjectID, CellSize = arg.CellSize, ReferenceDesign = arg.ReferenceDesign, }; if (arg.PositionsAreGrid) { arg2.ProfilePathNEE = new[] { arg.StartPoint, arg.EndPoint }.Select(x => new XYZ(x.Lon, x.Lat)).ToArray(); } else { if (siteModel != null) { arg2.ProfilePathNEE = DIContext.Obtain <ICoreXWrapper>().WGS84ToCalibration( siteModel.CSIB(), new[] { arg.StartPoint, arg.EndPoint } .ToCoreX_WGS84Point(), CoreX.Types.InputAs.Radians) .ToTRex_XYZ(); } } if (Design == null) { Log.LogWarning($"Failed to read file for design {arg.ReferenceDesign.DesignID} lock result was {LockResult}"); calcResult = DesignProfilerRequestResult.FailedToLoadDesignFile; return(null); } try { var result = Design.ComputeProfile(arg2.ProfilePathNEE, arg.CellSize); //Apply any offset to the profile if (arg.ReferenceDesign.Offset != 0) { for (var i = 0; i < result.Count; i++) { result[i] = new XYZS(result[i].X, result[i].Y, result[i].Z + arg.ReferenceDesign.Offset, result[i].Station, result[i].TriIndex); } } calcResult = DesignProfilerRequestResult.OK; return(result); } finally { Designs.UnLock(arg.ReferenceDesign.DesignID, Design); } }