public override void InternalFromBinary(IBinaryRawReader reader) { base.InternalFromBinary(reader); var version = VersionSerializationHelper.CheckVersionByte(reader, VERSION_NUMBER); if (version == 1) { ProjectID = reader.ReadGuid() ?? Guid.Empty; if (reader.ReadBoolean()) { (DesignDescriptor = new DesignDescriptor()).FromBinary(reader); } AsAtDate = DateTime.SpecifyKind(new DateTime(reader.ReadLong()), DateTimeKind.Utc); if (reader.ReadBoolean()) { (Extents = new BoundingWorldExtent3D()).FromBinary(reader); } if (reader.ReadBoolean()) { (ExistenceMap = new SubGridTreeSubGridExistenceBitMask()).FromBytes(reader.ReadByteArray()); } } }
/// <summary> /// Constructor /// </summary> public SubGridRequestsBase(ITRexTask tRexTask, Guid siteModelID, Guid requestID, Guid trexNodeId, GridDataType requestedGridDataType, bool includeSurveyedSurfaceInformation, ISubGridTreeBitMask prodDataMask, ISubGridTreeBitMask surveyedSurfaceOnlyMask, IFilterSet filters, DesignOffset referenceDesign, AreaControlSet areaControlSet, Action <TSubGridsRequestArgument> customArgumentInitializer, SubGridsRequestComputeStyle subGridsRequestComputeStyle) : this() { TRexTask = tRexTask; SiteModelID = siteModelID; RequestID = requestID; TRexNodeId = trexNodeId; RequestedGridDataType = requestedGridDataType; IncludeSurveyedSurfaceInformation = includeSurveyedSurfaceInformation; ProdDataMask = prodDataMask; SurveyedSurfaceOnlyMask = surveyedSurfaceOnlyMask; Filters = filters; ReferenceDesign = referenceDesign; AreaControlSet = areaControlSet; CustomArgumentInitializer = customArgumentInitializer; SubGridsRequestComputeStyle = SubGridsRequestComputeStyle; }
/// <summary> /// Integrates the cell passes processed from TAG files into sub grids within the live site model /// </summary> /// <param name="siteModelFromDatamodel">The site model to perform the change notifications for</param> /// <param name="task">The 'seed' task used as a hold all for aggregated machines</param> /// <param name="subGridIntegrator">The integrator to use to insert the new cell passes into the live site model</param> /// <param name="groupedAggregatedCellPasses">The set of all cell passes from all TAG files, grouped in to a single intermediary site model</param> /// <param name="numTagFilesRepresented">The number of TAG files represented in the data set being integrated</param> /// <param name="totalPassCountInAggregation">The sum total number of cell passes integrated in the live site model</param> private bool IntegrateCellPassesIntoLiveSiteModel(ISiteModel siteModelFromDatamodel, AggregatedDataIntegratorTask task, SubGridIntegrator subGridIntegrator, ISubGridTree groupedAggregatedCellPasses, int numTagFilesRepresented, out long totalPassCountInAggregation) { _log.LogInformation($"Aggregation Task Process --> Labeling aggregated cell pass with correct machine ID for {siteModelFromDatamodel.ID}"); totalPassCountInAggregation = 0; // This is a dirty map for the leaf sub grids and is stored as a bitmap grid // with one level fewer that the sub grid tree it is representing, and // with cells the size of the leaf sub grids themselves. As the cell coordinates // we have been given are with respect to the sub grid, we must transform them // into coordinates relevant to the dirty bitmap sub grid tree. _workingModelUpdateMap = new SubGridTreeSubGridExistenceBitMask { CellSize = SubGridTreeConsts.SubGridTreeDimension * siteModelFromDatamodel.CellSize, ID = siteModelFromDatamodel.ID }; // Integrate the cell pass data into the main site model and commit each sub grid as it is updated // ... first relabel the passes with the machine IDs from the persistent datamodel // Compute the vector of internal site model machine indexes between the intermediary site model constructed from the TAG files, // and the persistent site model the data us being processed into (short taskInternalMachineIndex, short datamodelInternalMachineIndex)[] internalMachineIndexMap = task.IntermediaryTargetMachines
/// <summary> /// Constructs a cell profile analyzer that analyzes cells in a cell profile vector /// </summary> /// <param name="siteModel"></param> /// <param name="pDExistenceMap"></param> /// <param name="filterSet"></param> /// <param name="cellLiftBuilder"></param> /// <param name="overrides"></param> public CellProfileAnalyzer(ISiteModel siteModel, ISubGridTreeBitMask pDExistenceMap, IFilterSet filterSet, ICellLiftBuilder cellLiftBuilder, IOverrideParameters overrides, ILiftParameters liftParams) : base(siteModel, pDExistenceMap, filterSet, overrides, liftParams) { CellLiftBuilder = cellLiftBuilder; PassFilter = filterSet.Filters[0].AttributeFilter; if (PassFilter.HasElevationRangeFilter && PassFilter.ElevationRangeDesign.DesignID != Guid.Empty) { var design = siteModel.Designs.Locate(PassFilter.ElevationRangeDesign.DesignID); if (design == null) { Log.LogError($"ElevationRangeDesign {PassFilter.ElevationRangeDesign.DesignID} is unknown in project {siteModel.ID}"); } else { PassFilterElevationRangeDesign = new DesignWrapper(PassFilter.ElevationRangeDesign, design); } } PassFilterAnnex = new CellPassAttributeFilterProcessingAnnex(); CellFilter = filterSet.Filters[0].SpatialFilter; }
/// <summary> /// Constructor for the sub grid retriever helper /// </summary> /// <param name="siteModel">The project this sub gris is being retrieved from</param> /// <param name="gridDataType">The type of client grid data sub grids to be returned by this retriever</param> /// <param name="storageProxy">The Ignite storage proxy to be used when requesting data from the persistent store</param> /// <param name="filter">The TRex spatial and attribute filtering description for the request</param> /// <param name="filterAnnex">An annex of data related to cell by cell filtering where the attributes related to that cell may change from cell to cell</param> /// <param name="hasOverrideSpatialCellRestriction">The spatially selected cells are masked by a rectangular restriction boundary</param> /// <param name="overrideSpatialCellRestriction"></param> /// <param name="prepareGridForCacheStorageIfNoSieving">The cell coordinate bounding box restricting cells involved in the request</param> /// <param name="maxNumberOfPassesToReturn">The maximum number of passes in a cell in a sub grid that will be considered when processing the request</param> /// <param name="areaControlSet">The skip/step area control set for selection of cells with sub grids for processing. Cells not identified by the control set will return null values.</param> /// <param name="populationControl">The delegate responsible for populating events depended on for processing the request.</param> /// <param name="pDExistenceMap">The production data existence map for the project the request relates to</param> /// <param name="overrides">The set of overriding machine event values to use</param> /// <param name="liftParams">The set of layer/lift analysis parameters to use</param> public ProgressiveVolumesSubGridRetriever(ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, bool prepareGridForCacheStorageIfNoSieving, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pDExistenceMap, IOverrideParameters overrides, ILiftParameters liftParams) : base(siteModel, gridDataType, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, prepareGridForCacheStorageIfNoSieving, maxNumberOfPassesToReturn, storageProxy, areaControlSet, populationControl, pDExistenceMap, overrides, liftParams) { // Clear any time element from the supplied filter. Time constraints ar derived from the startDate and endDate parameters filter.AttributeFilter.HasTimeFilter = false; // Clear any instruction in the filter to extract the earliest value - this has no meaning in progressive calculations filter.AttributeFilter.ReturnEarliestFilteredCellPass = false; // Remove any first/last/highest/lowest aspect from the filter - this has no meaning in progressive calculations filter.AttributeFilter.HasElevationTypeFilter = false; // Remove any machine filtering - the intent here is to examine volume progression over time, machine breakdowns don't make sense at this point filter.AttributeFilter.HasMachineFilter = false; }
/// <summary> /// Given a design used as an elevation range filter aspect, retrieve the existence map for the design and /// includes it in the supplied overall existence map for the query /// </summary> public static bool ProcessDesignElevationsForFilter(ISiteModel siteModel, //Guid siteModelID, ICombinedFilter filter, ISubGridTreeBitMask overallExistenceMap) { if (filter == null) { return(true); } if (overallExistenceMap == null) { return(false); } if (filter.AttributeFilter.HasElevationRangeFilter && filter.AttributeFilter.ElevationRangeDesign.DesignID != Guid.Empty) { var designExistenceMap = DIContext.Obtain <IExistenceMaps>().GetSingleExistenceMap (siteModel.ID, Consts.EXISTENCE_MAP_DESIGN_DESCRIPTOR, filter.AttributeFilter.ElevationRangeDesign.DesignID); if (designExistenceMap != null) { // Not sure this is really needed... designExistenceMap.CellSize = SubGridTreeConsts.SubGridTreeDimension * siteModel.CellSize; overallExistenceMap.SetOp_OR(designExistenceMap); } } return(true); }
/// <summary> /// Note: This method destructive modifies bitmask 'one' /// </summary> /// <param name="one"></param> /// <param name="two"></param> private void TestBitMasksAreTheSame(ISubGridTreeBitMask one, ISubGridTreeBitMask two) { // Ensure bit counts are the same one.CountBits().Should().Be(two.CountBits()); // XOR the two bit masks together. This should clear all set bits resulting in a BitCount of zero one.SetOp_XOR(two); one.CountBits().Should().Be(0); }
/// <summary> /// Notify all interested nodes in the immutable grid a site model has changed attributes /// </summary> public void ModelAttributesChanged(SiteModelNotificationEventGridMutability targetGrids, Guid siteModelID, bool existenceMapChanged = false, ISubGridTreeBitMask existenceMapChangeMask = null, bool designsChanged = false, bool surveyedSurfacesChanged = false, bool csibChanged = false, bool machinesChanged = false, bool machineTargetValuesChanged = false, bool machineDesignsModified = false, bool proofingRunsModified = false, bool alignmentsChanged = false, bool siteModelMarkedForDeletion = false) { var gridFactory = DIContext.Obtain <ITRexGridFactory>(); var evt = new SiteModelAttributesChangedEvent { SiteModelID = siteModelID, ExistenceMapModified = existenceMapChanged, ExistenceMapChangeMask = existenceMapChangeMask?.ToBytes(), CsibModified = csibChanged, DesignsModified = designsChanged, SurveyedSurfacesModified = surveyedSurfacesChanged, MachinesModified = machinesChanged, MachineTargetValuesModified = machineTargetValuesChanged, MachineDesignsModified = machineDesignsModified, ProofingRunsModified = proofingRunsModified, AlignmentsModified = alignmentsChanged, SiteModelMarkedForDeletion = siteModelMarkedForDeletion, ChangeEventUid = Guid.NewGuid(), TimeSentUtc = DateTime.UtcNow }; /* * if ((targetGrids & SiteModelNotificationEventGridMutability.NotifyImmutable) != 0) * gridFactory.Grid(StorageMutability.Immutable).GetMessaging().SendOrdered(evt, MESSAGE_TOPIC_NAME, _messageSendTimeout); * * if ((targetGrids & SiteModelNotificationEventGridMutability.NotifyMutable) != 0) * gridFactory.Grid(StorageMutability.Mutable).GetMessaging().SendOrdered(evt, MESSAGE_TOPIC_NAME, _messageSendTimeout); */ if ((targetGrids & SiteModelNotificationEventGridMutability.NotifyImmutable) != 0) { evt.SourceNodeUid = gridFactory.Grid(StorageMutability.Immutable).GetCluster().GetLocalNode().Id; SendInvokeStyleMessage("Immutable", evt); } if ((targetGrids & SiteModelNotificationEventGridMutability.NotifyMutable) != 0) { evt.SourceNodeUid = gridFactory.Grid(StorageMutability.Mutable).GetCluster().GetLocalNode().Id; SendInvokeStyleMessage("Mutable", evt); } }
/// <summary> /// Constructs a profile lift builder that analyzes cells in a cell profile vector /// </summary> public SummaryVolumesCellProfileAnalyzer(ISiteModel siteModel, ISubGridTreeBitMask pDExistenceMap, IFilterSet filterSet, IDesignWrapper referenceDesignWrapper, ICellLiftBuilder cellLiftBuilder, VolumeComputationType volumeType, IOverrideParameters overrides, ILiftParameters liftParams) : base(siteModel, pDExistenceMap, filterSet, overrides, liftParams) { svDesignWrapper = referenceDesignWrapper; VolumeType = volumeType; }
/// <summary> /// Constructs a profile lift builder that analyzes cells in a cell profile vector /// </summary> public CellProfileAnalyzerBase(ISiteModel siteModel, ISubGridTreeBitMask pDExistenceMap, IFilterSet filterSet, IOverrideParameters overrides, ILiftParameters liftParams) { SiteModel = siteModel; PDExistenceMap = pDExistenceMap; FilterSet = filterSet; Overrides = overrides; LiftParams = liftParams; Initialise(); }
/// <summary> /// Constructor for a TTMDesign that takes the underlying cell size for the site model that will be used when interpolating heights from the design surface /// </summary> public TTMDesign(double ACellSize) { Data = new TrimbleTINModel(); triangleItems = Data.Triangles.Items; vertexItems = Data.Vertices.Items; cellSize = ACellSize; // Create a sub grid tree bit mask index that holds one bit per on-the-ground // sub grid that intersects at least one triangle in the TTM. subGridIndex = new SubGridTreeSubGridExistenceBitMask { CellSize = SubGridTreeConsts.SubGridTreeDimension * ACellSize }; // Create the optimized sub grid tree spatial index that minimizes the number of allocations in the final result. SpatialIndexOptimised = new OptimisedSpatialIndexSubGridTree(SubGridTreeConsts.SubGridTreeLevels - 1, SubGridTreeConsts.SubGridTreeDimension * ACellSize); }
protected SubGridRetrieverBase(ISiteModel siteModel, GridDataType gridDataType, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, bool prepareGridForCacheStorageIfNoSieving, int maxNumberOfPassesToReturn, IStorageProxy storageProxy, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pDExistenceMap, IOverrideParameters overrides, ILiftParameters liftParams) { _segmentIterator = null; _cellPassIterator = null; _siteModel = siteModel; _gridDataType = gridDataType; _filter = filter; _filterAnnex = filterAnnex; _hasOverrideSpatialCellRestriction = hasOverrideSpatialCellRestriction; _overrideSpatialCellRestriction = overrideSpatialCellRestriction; _prepareGridForCacheStorageIfNoSieving = prepareGridForCacheStorageIfNoSieving; _maxNumberOfPassesToReturn = maxNumberOfPassesToReturn; _storageProxy = storageProxy; _populationControl = populationControl; _areaControlSet = areaControlSet; _pdExistenceMap = pDExistenceMap; _overrides = overrides; _liftParams = liftParams; // Create and configure the assignment context which is used to contain a filtered pass and // its attendant machine events and target values prior to assignment to the client sub grid. _assignmentContext = new FilteredValueAssignmentContext { Overrides = overrides, LiftParams = liftParams }; _filter.AttributeFilter.SiteModel = siteModel; _canUseGlobalLatestCells = _filter.AttributeFilter.LastRecordedCellPassSatisfiesFilter; }
/// <summary> /// Constructor for the sub grid retriever helper /// </summary> /// <param name="siteModel">The project this sub gris is being retrieved from</param> /// <param name="gridDataType">The type of client grid data sub grids to be returned by this retriever</param> /// <param name="storageProxy">The Ignite storage proxy to be used when requesting data from the persistent store</param> /// <param name="filter">The TRex spatial and attribute filtering description for the request</param> /// <param name="filterAnnex">An annex of data related to cell by cell filtering where the attributes related to that cell may change from cell to cell</param> /// <param name="hasOverrideSpatialCellRestriction">The spatially selected cells are masked by a rectangular restriction boundary</param> /// <param name="overrideSpatialCellRestriction"></param> /// <param name="prepareGridForCacheStorageIfNoSieving">The cell coordinate bounding box restricting cells involved in the request</param> /// <param name="maxNumberOfPassesToReturn">The maximum number of passes in a cell in a sub grid that will be considered when processing the request</param> /// <param name="areaControlSet">The skip/step area control set for selection of cells with sub grids for processing. Cells not identified by the control set will return null values.</param> /// <param name="populationControl">The delegate responsible for populating events depended on for processing the request.</param> /// <param name="pDExistenceMap">The production data existence map for the project the request relates to</param> /// <param name="overrides">The set of overriding machine event values to use</param> /// <param name="liftParams">The set of layer/lift analysis parameters to use</param> public SubGridRetriever(ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, bool prepareGridForCacheStorageIfNoSieving, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pDExistenceMap, IOverrideParameters overrides, ILiftParameters liftParams) : base(siteModel, gridDataType, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, prepareGridForCacheStorageIfNoSieving, maxNumberOfPassesToReturn, storageProxy, areaControlSet, populationControl, pDExistenceMap, overrides, liftParams) { }
/* TODO ColorPaletteClassType() * private TICDisplayPaletteBaseClass ColorPaletteClassType() * { * case FMode of * ...Height : Result = TICDisplayPalette_Height; * ...CCV : Result = TICDisplayPalette_CCV; * ...CCVPercent : Result = TICDisplayPalette_CCVPercent; * ...Latency : Result = TICDisplayPalette_RadioLatency; * ...PassCount : Result = TICDisplayPalette_PassCount; * ...PassCountSummary : Result = TICDisplayPalette_PassCountSummary; // Palettes are fixed three color palettes - display will use direct transitions * ...RMV : Result = TICDisplayPalette_RMV; * ...Frequency : Result = TICDisplayPalette_Frequency; * ...Amplitude : Result = TICDisplayPalette_Amplitude; * ...CutFill : Result = TICDisplayPalette_CutFill; * ...Moisture : Result = TICDisplayPalette_Moisture; * ...TemperatureSummary : Result = TICDisplayPaletteBase; //TICDisplayPalette_Temperature; * ...GPSMode : Result = TICDisplayPaletteBase; //TICDisplayPalette_GPSMode; * ...CCVSummary : Result = TICDisplayPaletteBase; //TICDisplayPalette_CCVSummary; * ...CCVPercentSummary : Result = TICDisplayPalette_CCVPercent; * ...CompactionCoverage : Result = TICDisplayPalette_CoverageOverlay; * ...VolumeCoverage : Result = TICDisplayPalette_VolumeOverlay; * ...MDP : Result = TICDisplayPalette_MDP; // ajr15167 * ...MDPSummary : Result = TICDisplayPaletteBase; * ...MDPPercent : Result = TICDisplayPalette_MDPPercent; * ...MDPPercentSummary : Result = TICDisplayPalette_MDPPercent; * ...MachineSpeed : Result = TICDisplayPalette_MachineSpeed; * ...CCVPercentChange : Result = TICDisplayPalette_CCVPercent; * ...TargetThicknessSummary : Result = TICDisplayPalette_VolumeOverlay; * ...TargetSpeedSummary : Result = TICDisplayPalette_SpeedSummary; * ...CCVChange : Result = TICDisplayPalette_CCVChange; * ...CCA : Result = TICDisplayPalette_CCA; * ...CCASummary : Result = TICDisplayPalette_CCASummary; * * else * SIGLogMessage.PublishNoODS(Self, Format('ColorPaletteClassType: Unknown display type: %d', [Ord(FMode)]), ...Assert); * Result = TICDisplayPaletteBase; * end; * end; */ /* TODO: ComputeCCAPalette * function ComputeCCAPalette :Boolean; * var * I, J, K :Integer; * ResponseVerb :...VerbBase; * ServerResult :TICServerRequestResult; * ResponseDataStream :TStream; * CCAMinimumPasses :...CCAMinPassesValue; * CCAColorScale :...CCAColorScale; * CCAPalette :TColorPalettes; * * begin * Result = False; * * ResponseVerb = nil; * try * if Length(FFilter1.Machines) > 0 then * FMachineID = FFilter1.Machines[0].ID // Must be set by caller * else * FMachineID = -1; // will fail call * if not Assigned(ASNodeImplInstance) or ASNodeImplInstance.ServiceStopped then * begin * SIGLogMessage.PublishNoODS(Self, Format('%s.Execute: Aborting request as service has been stopped', [Self.ClassName]), ...Warning); * Exit; * end; * * ASNodeImplInstance.PSLoadBalancer.LoadBalancedPSService.GetMachineCCAMinimumPassesValue(FDataModelID, FMachineID, FFilter1.StartTime, FFilter1.EndTime, FFilter1.LayerID, ResponseVerb); * if Assigned(ResponseVerb) then * with ResponseVerb as ...Verb_SendResponse do * begin * ServerResult = TICServerRequestResult(ResponseCode); * ResponseDataStream = ResponseData; * if (ServerResult = ...NoError) and assigned(ResponseData) then * begin * CCAMinimumPasses = ReadSmallIntFromStream(ResponseDataStream); * * Result = CCAMinimumPasses > 0; * * if not Result then * Exit; * * CCAColorScale = ...CCAColorScaleManager.CreateCoverageScale(CCAMinimumPasses); * try * SetLength(CCAPalette.Transitions, CCAColorScale.TotalColors); * * J = Low(CCAPalette.Transitions); * k = High(CCAPalette.Transitions); * for I = J to K do * begin * CCAPalette.Transitions[I].Color = CCAColorScale.ColorSegments[K - I].Color; * CCAPalette.Transitions[I].Value = I+1; * end; * CCAPalette.ConvertRGBToBGR; // gets done again but needed to match Anatoli palette test :) * WorkingColorPalette.PopulateFromPaletteColors(CCAPalette); * WorkingColorPalette.TransitionColors.ValuesCount = Length(CCAPalette.Transitions); * finally * if Assigned(CCAColorScale) then * FreeAndNil(CCAColorScale); * end; * end * else * SIGLogMessage.PublishNoODS(Self, Format('%s.Execute: GetMachineCCAMinimumPassesValue Failed for InternalSiteModelMachineIndex: %d. ReturnCode:%d', [Self.ClassName, FMachineID, Ord(ServerResult)]), ...Warning); * end; * finally * if Assigned(ResponseVerb) then * FreeAndNil(ResponseVerb); * end; * end; */ /* TODO: CreateAndInitialiseWorkingColorPalette * function CreateAndInitialiseWorkingColorPalette :Boolean; * begin * Result = True; * * // Create a scaled palette to use when rendering the data * try * if ColorPaletteClassType<> Nil then * begin * * WorkingColorPalette = ColorPaletteClassType.Create; * WorkingColorPalette.SmoothPalette = FMode = ...CutFill; * * // CCASummary is done per machine id * if FMode in [...CCA, ...CCASummary] * then * Result = ComputeCCAPalette * else * begin * if Length(FColorPalettes.Transitions) = 0 then * WorkingColorPalette.SetToDefaults * else * WorkingColorPalette.PopulateFromPaletteColors(FColorPalettes); * end; * * if Result then * WorkingColorPalette.ComputePalette; * end * else * WorkingColorPalette = Nil; * * Except * On e:Exception do * SIGLogMessage.PublishNoODS(Self, Format('%s.Execute: Error: %s ', [Self.ClassName, e.Message]), ...Exception); * end; * end; */ /// <summary> /// Renders all sub grids in a representational style that indicates where there is data, but nothing else. This is used for large scale displays /// (zoomed out a lot) where meaningful detail cannot be drawn on the tile /// </summary> private SKBitmap RenderTileAsRepresentationalDueToScale(ISubGridTreeBitMask overallExistenceMap) { using (var RepresentationalDisplay = PVMDisplayerFactory.GetDisplayer(Mode /*, FICOptions*/)) { using (var mapView = new MapSurface { SquareAspect = false }) { mapView.SetRotation(TileRotation); RepresentationalDisplay.MapView = mapView; RepresentationalDisplay.MapView.SetBounds(NPixelsX, NPixelsY); RepresentationalDisplay.MapView.SetWorldBounds(NEECoords[0].X, NEECoords[0].Y, NEECoords[0].X + WorldTileWidth, NEECoords[0].Y + WorldTileHeight, 0); // Iterate over all the bits in the sub grids drawing a rectangle for each one on the tile being rendered if (overallExistenceMap.ScanSubGrids(RotatedTileBoundingExtents, leaf => { leaf.CalculateWorldOrigin(out var WorldOriginX, out var WorldOriginY); (leaf as SubGridTreeLeafBitmapSubGrid)?.Bits.ForEachSetBit((x, y) => { RepresentationalDisplay.MapView.DrawRect(WorldOriginX + (x * overallExistenceMap.CellSize), WorldOriginY + (y * overallExistenceMap.CellSize), overallExistenceMap.CellSize, overallExistenceMap.CellSize, true, RepresentColor); }); return(true); })) { // Remove the canvas from the map view to prevent it's disposal (it's being returned to the caller) var canvas = RepresentationalDisplay.MapView.BitmapCanvas; RepresentationalDisplay.MapView.BitmapCanvas = null; return(canvas); } } } return(null); // It did not work out... }
/// <summary> /// Creates a change map buffer queue item and places it in to the cache for the service processor to collect /// </summary> public void Notify(Guid projectUid, DateTime insertUtc, ISubGridTreeBitMask changeMap, SiteModelChangeMapOrigin origin, SiteModelChangeMapOperation operation) { try { _log.LogInformation($"Adding site model change map notification for project {projectUid}"); _queueCache.Put(new SiteModelChangeBufferQueueKey(projectUid, insertUtc), new SiteModelChangeBufferQueueItem { ProjectUID = projectUid, InsertUTC = insertUtc, Operation = operation, Origin = origin, Content = changeMap?.ToBytes() }); } catch (Exception e) { _log.LogError(e, "Exception notifying site model change map"); } }
/// <summary> /// Configures a new profile builder that provides the three core builders used in profiling: construction of cell vector from profile line, /// profile analysis orchestration and per cell layer/statistics calculation /// </summary> public void Configure(ProfileStyle profileStyle, ISiteModel siteModel, ISubGridTreeBitMask productionDataExistenceMap, GridDataType gridDataType, IFilterSet filterSet, IDesignWrapper referenceDesignWrapper, IFilteredValuePopulationControl PopulationControl, ICellPassFastEventLookerUpper CellPassFastEventLookerUpper, VolumeComputationType volumeType, IOverrideParameters overrides, ILiftParameters liftParams, bool slicerToolUsed = true) { CellLiftBuilder = factory.NewCellLiftBuilder(siteModel, gridDataType, PopulationControl, filterSet, CellPassFastEventLookerUpper); CellProfileBuilder = factory.NewCellProfileBuilder(siteModel, filterSet, referenceDesignWrapper, slicerToolUsed); CellProfileAnalyzer = factory.NewCellProfileAnalyzer( profileStyle, siteModel, productionDataExistenceMap, filterSet, referenceDesignWrapper, CellLiftBuilder, volumeType, overrides, liftParams); }
/// <summary> /// Perform the request extracting all required existence maps and combine them together /// </summary> public ISubGridTreeBitMask Execute(INonSpatialAffinityKey[] keys) { ISubGridTreeBitMask combinedMask = null; foreach (var key in keys) { var Mask = _singleRequest.Execute(key); if (Mask != null) { if (combinedMask == null) { combinedMask = Mask; } else { combinedMask.SetOp_OR(Mask); } } } return(combinedMask); }
private void TestSiteModelAndChangeMap_Ingest(ISiteModel siteModel, ISubGridTreeBitMask changeMap, int finalBitCount) { var insertUtc = DateTime.UtcNow; var key = new SiteModelChangeBufferQueueKey(siteModel.ID, insertUtc); var value = new SiteModelChangeBufferQueueItem { ProjectUID = siteModel.ID, MachineUid = siteModel.Machines.First().ID, InsertUTC = insertUtc, Operation = SiteModelChangeMapOperation.AddSpatialChanges, Origin = SiteModelChangeMapOrigin.Ingest, Content = changeMap.ToBytes() }; PerformProcessEvent(key, value); // Check there is now a change map item for the site model with the given content var changeMapProxy = new SiteModelChangeMapProxy(); var resultChangeMap = changeMapProxy.Get(key.ProjectUID, value.MachineUid); resultChangeMap.Should().NotBeNull(); resultChangeMap.CountBits().Should().Be(finalBitCount); }
/// <summary> /// Add a new surveyed surface to a site model /// </summary> public ISurveyedSurface Add(Guid siteModelUid, DesignDescriptor designDescriptor, DateTime asAtDate, BoundingWorldExtent3D extents, ISubGridTreeBitMask existenceMap) { if (asAtDate.Kind != DateTimeKind.Utc) { throw new ArgumentException("AsAtDate must be a UTC date time"); } if (extents == null) { throw new ArgumentNullException(nameof(extents)); } if (existenceMap == null) { throw new ArgumentNullException(nameof(existenceMap)); } var ss = Load(siteModelUid); var newSurveyedSurface = ss.AddSurveyedSurfaceDetails(designDescriptor.DesignID, designDescriptor, asAtDate, extents); // Store the existence map into the cache using var stream = existenceMap.ToStream(); var fileName = BaseExistenceMapRequest.CacheKeyString(ExistenceMaps.Interfaces.Consts.EXISTENCE_SURVEYED_SURFACE_DESCRIPTOR, designDescriptor.DesignID); if (_writeStorageProxy.WriteStreamToPersistentStore(siteModelUid, fileName, FileSystemStreamType.DesignTopologyExistenceMap, stream, existenceMap) != FileSystemErrorStatus.OK) { _log.LogError("Failed to write existence map to persistent store for key {fileName}"); return(null); } // Store performs Commit() operation Store(siteModelUid, ss); return(newSurveyedSurface); }
/// <summary> /// Given a filter compute which of the surfaces in the list match any given time aspect /// of the filter, and the overall existence map of the surveyed surfaces that match the filter. /// ComparisonList denotes a possibly pre-filtered set of surfaces for another filter; if this is the same as the /// filtered set of surfaces then the overall existence map for those surfaces will not be computed as it is /// assumed to be the same. /// </summary> public bool ProcessSurveyedSurfacesForFilter(Guid siteModelId, ICombinedFilter filter, ISurveyedSurfaces comparisonList, ISurveyedSurfaces filteredSurveyedSurfaces, ISubGridTreeBitMask overallExistenceMap) { // Filter out any surveyed surfaces which don't match current filter (if any) - realistically, this is time filters we're thinking of here FilterSurveyedSurfaceDetails(filter.AttributeFilter.HasTimeFilter, filter.AttributeFilter.StartTime, filter.AttributeFilter.EndTime, filter.AttributeFilter.ExcludeSurveyedSurfaces(), filteredSurveyedSurfaces, filter.AttributeFilter.SurveyedSurfaceExclusionList); if (filteredSurveyedSurfaces != null) { if (filteredSurveyedSurfaces.IsSameAs(comparisonList)) { return(true); } if (filteredSurveyedSurfaces.Count > 0) { var surveyedSurfaceExistenceMap = GetExistenceMaps().GetCombinedExistenceMap(siteModelId, filteredSurveyedSurfaces.Select(x => new Tuple <long, Guid>(Consts.EXISTENCE_SURVEYED_SURFACE_DESCRIPTOR, x.ID)).ToArray()); if (overallExistenceMap == null) { return(false); } overallExistenceMap.SetOp_OR(surveyedSurfaceExistenceMap); } } return(true); }
/// <summary> /// Creates a new builder responsible for analyzing profile information for a cell or cells identified along a profile line /// </summary> public ICellProfileAnalyzer <T> NewCellProfileAnalyzer(ProfileStyle profileStyle, ISiteModel siteModel, ISubGridTreeBitMask pDExistenceMap, IFilterSet filterSet, IDesignWrapper referenceDesignWrapper, ICellLiftBuilder cellLiftBuilder, VolumeComputationType volumeComputationType, IOverrideParameters overrides, ILiftParameters liftParams) { switch (profileStyle) { case ProfileStyle.CellPasses: return(DIContext.Obtain <Func <ISiteModel, ISubGridTreeBitMask, IFilterSet, ICellLiftBuilder, IOverrideParameters, ILiftParameters, ICellProfileAnalyzer <T> > >() (siteModel, pDExistenceMap, filterSet, cellLiftBuilder, overrides, liftParams)); case ProfileStyle.SummaryVolume: return(DIContext.Obtain <Func <ISiteModel, ISubGridTreeBitMask, IFilterSet, IDesignWrapper, ICellLiftBuilder, VolumeComputationType, IOverrideParameters, ILiftParameters, ICellProfileAnalyzer <T> > >() (siteModel, pDExistenceMap, filterSet, referenceDesignWrapper, cellLiftBuilder, volumeComputationType, overrides, liftParams)); default: throw new ArgumentOutOfRangeException(nameof(profileStyle), profileStyle, null); } }
/// <summary> /// Performs execution business logic for this executor /// </summary> public ISurveyedSurface Execute(Guid projectUid, DesignDescriptor designDescriptor, DateTime asAtDate, BoundingWorldExtent3D extents, ISubGridTreeBitMask existenceMap) { try { var siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(projectUid, false); if (siteModel == null) { _log.LogError($"Site model {projectUid} not found"); return(null); } var surveyedSurface = DIContext.Obtain <ISurveyedSurfaceManager>().Add(projectUid, designDescriptor, asAtDate, extents, existenceMap); if (surveyedSurface == null) { _log.LogError($"Failed to add surveyed surface file {designDescriptor}, asAtDate {asAtDate} to project {projectUid}"); } return(surveyedSurface); } catch (Exception e) { _log.LogError(e, "Execute: Exception: "); return(null); } }
/// <summary> /// Add a new design to a site model /// </summary> public IDesign Add(Guid siteModelId, DesignDescriptor designDescriptor, BoundingWorldExtent3D extents, ISubGridTreeBitMask existenceMap) { if (extents == null) { throw new ArgumentNullException(nameof(extents)); } if (existenceMap == null) { throw new ArgumentNullException(nameof(existenceMap)); } // Add the design to the designs list var designs = Load(siteModelId); var result = designs.AddDesignDetails(designDescriptor.DesignID, designDescriptor, extents); // Store the existence map into the cache using var stream = existenceMap.ToStream(); var fileName = BaseExistenceMapRequest.CacheKeyString(ExistenceMaps.Interfaces.Consts.EXISTENCE_MAP_DESIGN_DESCRIPTOR, designDescriptor.DesignID); if (_writeStorageProxy.WriteStreamToPersistentStore(siteModelId, fileName, FileSystemStreamType.DesignTopologyExistenceMap, stream, existenceMap) != FileSystemErrorStatus.OK) { _log.LogError("Failed to write existence map to persistent store for key {fileName}"); return(null); } // Store performs Commit() operation Store(siteModelId, designs); return(result); }
/// <summary> /// Performs execution business logic for this executor /// </summary> public IDesign Execute(Guid projectUid, DesignDescriptor designDescriptor, BoundingWorldExtent3D extents, ISubGridTreeBitMask existenceMap) { try { var siteModel = DIContext.Obtain <ISiteModels>().GetSiteModel(projectUid, false); if (siteModel == null) { _log.LogError($"Site model {projectUid} not found"); return(null); } var design = DIContext.Obtain <IDesignManager>().Add(projectUid, designDescriptor, extents, existenceMap); if (design == null) { _log.LogError($"Failed to add design file {designDescriptor} to project {projectUid}"); } return(design); } catch (Exception e) { _log.LogError(e, "Execute: Exception: "); return(null); } }
public RequestErrorStatus ExecutePipeline() { SubGridPipelineAggregative <SubGridsRequestArgument, SimpleVolumesResponse> PipeLine; var Result = RequestErrorStatus.Unknown; var PipelineAborted = false; // bool ShouldAbortDueToCompletedEventSet = false; try { ProdDataExistenceMap = SiteModel.ExistenceMap; try { if (ActiveDesign != null && (VolumeType == VolumeComputationType.BetweenFilterAndDesign || VolumeType == VolumeComputationType.BetweenDesignAndFilter)) { if (ActiveDesign == null || ActiveDesign.Design.DesignDescriptor.IsNull) { Log.LogError($"No design provided to prod data/design volumes calc for datamodel {SiteModel.ID}"); return(RequestErrorStatus.NoDesignProvided); } DesignSubgridOverlayMap = GetExistenceMaps().GetSingleExistenceMap(SiteModel.ID, ExistenceMaps.Interfaces.Consts.EXISTENCE_MAP_DESIGN_DESCRIPTOR, ActiveDesign.Design.ID); if (DesignSubgridOverlayMap == null) { return(RequestErrorStatus.NoDesignProvided); } } OverallExistenceMap = new SubGridTreeSubGridExistenceBitMask(); // Work out the surveyed surfaces and coverage areas that need to be taken into account var SurveyedSurfaces = SiteModel.SurveyedSurfaces; if (SurveyedSurfaces != null) { // See if we need to handle surveyed surface data for 'base' // Filter out any surveyed surfaces which don't match current filter (if any) - realistically, this is time filters we're thinking of here if (VolumeType == VolumeComputationType.Between2Filters || VolumeType == VolumeComputationType.BetweenFilterAndDesign) { if (!SurveyedSurfaces.ProcessSurveyedSurfacesForFilter(SiteModel.ID, BaseFilter, FilteredTopSurveyedSurfaces, FilteredBaseSurveyedSurfaces, OverallExistenceMap)) { return(RequestErrorStatus.Unknown); } } // See if we need to handle surveyed surface data for 'top' // Filter out any surveyed surfaces which don't match current filter (if any) - realistically, this is time filters we're thinking of here if (VolumeType == VolumeComputationType.Between2Filters || VolumeType == VolumeComputationType.BetweenDesignAndFilter) { if (!SurveyedSurfaces.ProcessSurveyedSurfacesForFilter(SiteModel.ID, TopFilter, FilteredBaseSurveyedSurfaces, FilteredTopSurveyedSurfaces, OverallExistenceMap)) { return(RequestErrorStatus.Unknown); } } } // Add in the production data existence map to the computed surveyed surfaces existence maps OverallExistenceMap.SetOp_OR(ProdDataExistenceMap); // If necessary, impose spatial constraints from filter design(s) if (VolumeType == VolumeComputationType.Between2Filters || VolumeType == VolumeComputationType.BetweenFilterAndDesign) { if (!DesignFilterUtilities.ProcessDesignElevationsForFilter(SiteModel, BaseFilter, OverallExistenceMap)) { return(RequestErrorStatus.Unknown); } } if (VolumeType == VolumeComputationType.Between2Filters || VolumeType == VolumeComputationType.BetweenDesignAndFilter) { if (!DesignFilterUtilities.ProcessDesignElevationsForFilter(SiteModel, TopFilter, OverallExistenceMap)) { return(RequestErrorStatus.Unknown); } } var PipelinedTask = new VolumesComputationTask { Aggregator = Aggregator }; try { PipeLine = new SubGridPipelineAggregative <SubGridsRequestArgument, SimpleVolumesResponse>(/*0, */ PipelinedTask); PipelinedTask.PipeLine = PipeLine; ConfigurePipeline(PipeLine); if (PipeLine.Initiate()) { var completionResult = PipeLine.WaitForCompletion(); Log.LogInformation(completionResult ? "WaitForCompletion successful" : $"WaitForCompletion timed out with {PipeLine.SubGridsRemainingToProcess} sub grids remaining to be processed"); if (PipeLine.SubGridsRemainingToProcess > 0) { Log.LogInformation($"Pipeline completed with {PipeLine.SubGridsRemainingToProcess} sub grids remaining to be processed"); } } /* * while not FPipeLine.AllFinished and not FPipeLine.PipelineAborted do * begin * WaitResult := FPipeLine.CompleteEvent.WaitFor(5000); * * if VLPDSvcLocations.Debug_EmitSubgridPipelineProgressLogging then * begin * if ((FEpochCount > 0) or (FPipeLine.SubmissionNode.TotalNumberOfSubgridsScanned > 0)) and * ((FPipeLine.OperationNode.NumPendingResultsReceived > 0) or (FPipeLine.OperationNode.OustandingSubgridsToOperateOn > 0)) then * SIGLogMessage.PublishNoODS(Self, Format('%s: Pipeline (request %d, model %d): #Progress# - Scanned = %d, Submitted = %d, Processed = %d (with %d pending and %d results outstanding)', * [Self.ClassName, * FRequestDescriptor, FPipeline.ProjectUid, * FPipeLine.SubmissionNode.TotalNumberOfSubgridsScanned, * FPipeLine.SubmissionNode.TotalSumbittedSubgridRequests, * FPipeLine.OperationNode.TotalOperatedOnSubgrids, * FPipeLine.OperationNode.NumPendingResultsReceived, * FPipeLine.OperationNode.OustandingSubgridsToOperateOn]), slmcDebug); * end; * * if (WaitResult = wrSignaled) and not FPipeLine.AllFinished and not FPipeLine.PipelineAborted and not FPipeLine.Terminated then * begin * if ShouldAbortDueToCompletedEventSet then * begin * if (FPipeLine.OperationNode.NumPendingResultsReceived > 0) or (FPipeLine.OperationNode.OustandingSubgridsToOperateOn > 0) then * SIGLogMessage.PublishNoODS(Self, Format('%s: Pipeline (request %d, model %d) being aborted as it''s completed event has remained set but still has work to do (%d outstanding subgrids, %d pending results to process) over a sleep epoch', * [Self.ClassName, * FRequestDescriptor, FPipeline.ProjectUid, * FPipeLine.OperationNode.OustandingSubgridsToOperateOn, * FPipeLine.OperationNode.NumPendingResultsReceived]), slmcError); * FPipeLine.Abort; * ASNodeImplInstance.AsyncResponder.ASNodeResponseProcessor.PerformTaskCancellation(FPipelinedTask); * Exit; * end * else * begin * if (FPipeLine.OperationNode.NumPendingResultsReceived > 0) or (FPipeLine.OperationNode.OustandingSubgridsToOperateOn > 0) then * SIGLogMessage.PublishNoODS(Self, Format('%s: Pipeline (request %d, model %d) has it''s completed event set but still has work to do (%d outstanding subgrids, %d pending results to process)', * [Self.ClassName, * FRequestDescriptor, FPipeline.ProjectUid, * FPipeLine.OperationNode.OustandingSubgridsToOperateOn, * FPipeLine.OperationNode.NumPendingResultsReceived]), slmcDebug); * Sleep(500); * ShouldAbortDueToCompletedEventSet := True; * end; * end; * * if FPipeLine.TimeToLiveExpired then * begin * FAbortedDueToTimeout := True; * FPipeLine.Abort; * ASNodeImplInstance.AsyncResponder.ASNodeResponseProcessor.PerformTaskCancellation(FPipelinedTask); * * // The pipeline has exceed its allotted time to complete. It will now * // be aborted and this request will be failed. * SIGLogMessage.PublishNoODS(Self, Format('%s: Pipeline (request %d) aborted due to time to live expiration (%d seconds)', * [Self.ClassName, FRequestDescriptor, FPipeLine.TimeToLiveSeconds]), slmcError); * Exit; * end; */ PipelineAborted = PipeLine.Aborted; if (!PipeLine.Terminated && !PipeLine.Aborted) { Result = RequestErrorStatus.OK; } } finally { if (AbortedDueToTimeout) { Result = RequestErrorStatus.AbortedDueToPipelineTimeout; } else if (PipelinedTask.IsCancelled || PipelineAborted) { Result = RequestErrorStatus.RequestHasBeenCancelled; } } } catch (Exception e) { Log.LogError(e, "ExecutePipeline raised exception"); } return(Result); } catch (Exception e) { Log.LogError(e, "Exception"); } return(RequestErrorStatus.Unknown); }
/// <summary> /// Invalidates sub grids held within all cache contexts for a project that are sensitive to /// ingest of production data (eg: from TAG files) /// </summary> public void InvalidateDueToProductionDataIngest(Guid projectUid, Guid changeEventUid, ISubGridTreeBitMask mask) { var numInvalidatedSubGrids = 0; var numScannedSubGrids = 0; var startTime = DateTime.UtcNow; var contextCount = 0; lock (_contexts) { if (_projectContexts.TryGetValue(projectUid, out var projectContexts)) { if (projectContexts == null || projectContexts.Count == 0) { return; } contextCount = projectContexts.Count; // Walk through the cloned list of contexts evicting all relevant element per the supplied mask // Only hold a Contexts lock for the duration of a single context. 'Eviction' is really marking the // element as dirty to amortize the effort in executing the invalidation across cache accessor contexts. foreach (var context in projectContexts) { // Empty contexts are ignored if (context.TokenCount == 0) { return; } // If the context in question is not sensitive to production data ingest then ignore it if (!context.Sensitivity.HasFlag(TRexSpatialMemoryCacheInvalidationSensitivity.ProductionDataIngest)) { return; } // Iterate across all elements in the mask: // 1. Locate the cache entry // 2. Mark it as dirty mask.ScanAllSetBitsAsSubGridAddresses(origin => { context.InvalidateSubGrid(origin.X, origin.Y, out var subGridPresentForInvalidation); numScannedSubGrids++; if (subGridPresentForInvalidation) { numInvalidatedSubGrids++; } }); } } } _log.LogInformation($"Invalidated {numInvalidatedSubGrids} out of {numScannedSubGrids} scanned sub grid from {contextCount} contexts in {DateTime.UtcNow - startTime} [project {projectUid}, change event ID {changeEventUid}]"); }
public ISubGridRetriever Instance(ISubGridsRequestArgument subGridsRequestArgument, ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, ICellPassAttributeFilterProcessingAnnex filterAnnex, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pdExistenceMap, ITRexSpatialMemoryCacheContext[] subGridCacheContexts, IOverrideParameters overrides, ILiftParameters liftParams) { if (gridDataType == GridDataType.ProgressiveVolumes) { var retriever = new ProgressiveVolumesSubGridRetriever(siteModel, gridDataType, storageProxy, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, subGridCacheContexts != null, maxNumberOfPassesToReturn, areaControlSet, populationControl, pdExistenceMap, overrides, liftParams); if (subGridsRequestArgument is IProgressiveVolumesSubGridsRequestArgument argument) { retriever.StartDate = argument.StartDate; retriever.EndDate = argument.EndDate; retriever.Interval = argument.Interval; } else { throw new ArgumentException($"Argument passed to sub grid retriever factory for progressive volumes retriever construction is not an expected type: {subGridsRequestArgument.GetType()}"); } return(retriever); } else { var retriever = new SubGridRetriever(siteModel, gridDataType, storageProxy, filter, filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, subGridCacheContexts != null, maxNumberOfPassesToReturn, areaControlSet, populationControl, pdExistenceMap, overrides, liftParams); return(retriever); } }
/// <summary> /// Constructor that accepts the common parameters around a set of sub grids the requester will be asked to process /// and initializes the requester state ready to start processing individual sub grid requests. /// </summary> public void Initialize(ISubGridsRequestArgument subGridsRequestArgument, ISiteModel siteModel, GridDataType gridDataType, IStorageProxy storageProxy, ICombinedFilter filter, bool hasOverrideSpatialCellRestriction, BoundingIntegerExtent2D overrideSpatialCellRestriction, int maxNumberOfPassesToReturn, AreaControlSet areaControlSet, IFilteredValuePopulationControl populationControl, ISubGridTreeBitMask pdExistenceMap, ITRexSpatialMemoryCache subGridCache, ITRexSpatialMemoryCacheContext[] subGridCacheContexts, ISurveyedSurfaces filteredSurveyedSurfaces, ISurfaceElevationPatchRequest surfaceElevationPatchRequest, IOverrideParameters overrides, ILiftParameters liftParams) { _siteModel = siteModel; _gridDataType = gridDataType; _filter = filter; _hasOverrideSpatialCellRestriction = hasOverrideSpatialCellRestriction; _overrideSpatialCellRestriction = overrideSpatialCellRestriction; _retriever = DIContext.Obtain <ISubGridRetrieverFactory>().Instance(subGridsRequestArgument, siteModel, gridDataType, storageProxy, filter, _filterAnnex, hasOverrideSpatialCellRestriction, overrideSpatialCellRestriction, maxNumberOfPassesToReturn, areaControlSet, populationControl, pdExistenceMap, subGridCacheContexts, overrides, liftParams); _returnEarliestFilteredCellPass = _filter.AttributeFilter.ReturnEarliestFilteredCellPass; _processingMap = new SubGridTreeBitmapSubGridBits(SubGridBitsCreationOptions.Unfilled); _surfaceElevationPatchRequest = surfaceElevationPatchRequest; _subGridCache = subGridCache; _subGridCacheContexts = subGridCacheContexts; _surveyedSurfacePatchType = _filter.AttributeFilter.ReturnEarliestFilteredCellPass ? SurveyedSurfacePatchType.EarliestSingleElevation : SurveyedSurfacePatchType.LatestSingleElevation; _filteredSurveyedSurfaces = filteredSurveyedSurfaces; _filteredSurveyedSurfaces?.SortChronologically(_surveyedSurfacePatchType == SurveyedSurfacePatchType.LatestSingleElevation); _filteredSurveyedSurfacesAsGuidArray = _filteredSurveyedSurfaces?.Select(x => x.ID).ToArray() ?? new Guid[0]; var elevRangeDesignFilter = _filter.AttributeFilter.ElevationRangeDesign; if (elevRangeDesignFilter.DesignID != Guid.Empty) { var design = _siteModel.Designs.Locate(elevRangeDesignFilter.DesignID); if (design == null) { _log.LogError($"ElevationRangeDesign {elevRangeDesignFilter.DesignID} is unknown in project {siteModel.ID}"); } else { _elevationRangeDesign = new DesignWrapper(elevRangeDesignFilter, design); } } if (_filter.SpatialFilter.IsDesignMask) { _surfaceDesignMaskDesign = _siteModel.Designs.Locate(_filter.SpatialFilter.SurfaceDesignMaskDesignUid); } _filter.AttributeFilter.SiteModel = _siteModel; }