コード例 #1
0
        public void Test_SubGridTree_InvalidCreation_TreeLevels()
        {
            // Test creating invalid subgrid trees
            ISubGridTree invalid = null;

            try
            {
                invalid = new SubGridTree(0, 1.0, new SubGridFactory <NodeSubGrid, LeafSubGrid>());
                Assert.True(false, "SubGridTree permitted creation with invalid subgrid tree level");
            }
            catch (Exception e)
            {
                Assert.True(e is ArgumentException, "Invalid exception raised for invalid argument to SubGridTree constructor");
            }

            try
            {
                invalid = new SubGridTree(10, 1.0, new SubGridFactory <NodeSubGrid, LeafSubGrid>());
                Assert.True(false, "SubGridTree permitted creation with invalid subgrid tree level");
            }
            catch (Exception e)
            {
                Assert.True(e is ArgumentException, "Invalid exception raised for invalid argument to SubGridTree constructor");
            }

            try
            {
                invalid = new SubGridTree(10, 1.0, new SubGridFactory <NodeSubGrid, LeafSubGrid>());
                Assert.True(false, "SubGridTree permitted creation with invalid subgrid tree level");
            }
            catch (Exception e)
            {
                Assert.True(e is ArgumentException, "Invalid exception raised for invalid argument to SubGridTree constructor");
            }
        }
コード例 #2
0
        /// <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
コード例 #3
0
        /// <summary>
        /// Computes a tight bounding extent around the elevation values stored in the sub grid tree
        /// </summary>
        private static BoundingWorldExtent3D DataStoreExtents(ISubGridTree dataStore)
        {
            var computedGridExtent = BoundingWorldExtent3D.Inverted();

            dataStore.ScanAllSubGrids(subGrid =>
            {
                var items = ((GenericLeafSubGrid <float>)subGrid).Items;
                SubGridUtilities.SubGridDimensionalIterator((x, y) =>
                {
                    var elev = items[x, y];
                    if (elev != Common.Consts.NullHeight)
                    {
                        computedGridExtent.Include(subGrid.OriginX + x, subGrid.OriginY + y, elev);
                    }
                });

                return(true);
            });

            if (computedGridExtent.IsValidPlanExtent)
            {
                computedGridExtent.Offset(-SubGridTreeConsts.DefaultIndexOriginOffset, -SubGridTreeConsts.DefaultIndexOriginOffset);
            }

            // Convert the grid rectangle to a world rectangle, padding out the 3D bound by a small margin to avoid edge effects in calculations
            var computedWorldExtent = new BoundingWorldExtent3D
                                          ((computedGridExtent.MinX - 1.01) * dataStore.CellSize,
                                          (computedGridExtent.MinY - 1.01) * dataStore.CellSize,
                                          (computedGridExtent.MaxX + 1.01) * dataStore.CellSize,
                                          (computedGridExtent.MaxY + 1.01) * dataStore.CellSize,
                                          computedGridExtent.MinZ - 0.01, computedGridExtent.MaxZ + 0.01);

            return(computedWorldExtent);
        }
コード例 #4
0
 public LeafSubGrid(ISubGridTree owner,
                    ISubGrid parent,
                    byte level) : base(owner, parent, level)
 {
     // Assert level = tree.NumLevels (leaves are only at the tips)
     if (owner != null && level != owner.NumLevels)
     {
         throw new ArgumentException("Requested level for leaf sub grid <> number of levels in tree", nameof(level));
     }
 }
コード例 #5
0
        /// <summary>
        /// Constructor the the base client sub grid. This decorates the standard (owner, parent, level)
        /// constructor from the base with the cell size and index origin offset parameters from the sub grid tree
        /// this leaf is derived from.
        /// </summary>
        protected ClientLeafSubGrid(ISubGridTree owner,
                                    ISubGrid parent,
                                    byte level,
                                    double cellSize,
                                    int indexOriginOffset) : base(owner, parent, level)
        {
            CellSize          = cellSize;
            IndexOriginOffset = indexOriginOffset;

            _gridDataType = GridDataType.All; // Default to 'all', descendant specialized classes will set appropriately

            TopLayerOnly       = false;
            ProfileDisplayMode = DisplayMode.Height;
        }
コード例 #6
0
        /// <summary>
        /// Provides Read() semantics for a sub grid tree against a BinaryReader
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="header"></param>
        /// <param name="version"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        public static bool Read(ISubGridTree tree, string header, int version, BinaryReader reader)
        {
            string Header  = reader.ReadString();
            int    Version = reader.ReadInt32();
            long   Size    = reader.ReadInt64();

            if (Header != header || Version != version || Size == 0 || Size != reader.BaseStream.Length)
            {
                Log.LogError($"Header, version or stream size mismatch reading spatial sub grid index. Header={Header} (expected {header}), Version={Version} (expected {version}), Size={reader.BaseStream.Length} (expected {Size})");
                return(false);
            }

            return(SerialiseIn(tree, reader));
        }
コード例 #7
0
        public void Test_SubGridTree_InvalidCreation_SubgridFactory()
        {
            // Test creating with invalid factory
            ISubGridTree invalid = null;

            try
            {
                invalid = new SubGridTree(SubGridTreeConsts.SubGridTreeLevels, 1.0, null);
                Assert.True(false, "SubGridTree permitted creation with invalid subgrid tree cell size");
            }
            catch (Exception e)
            {
                Assert.True(e is ArgumentException, "Invalid exception raised for invalid argument to SubGridTree constructor");
            }
        }
コード例 #8
0
        /// <summary>
        /// Serializes all the sub grids in the tree out to the writer
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="writer"></param>
        /// <returns></returns>
        static bool SerializeOut(ISubGridTree tree, BinaryWriter writer)
        {
            long SubGridCount = tree.CountLeafSubGridsInMemory();

            writer.Write(tree.ID.ToByteArray());
            writer.Write(SubGridCount);

            return(tree.ScanAllSubGrids(subGrid =>
            {
                // Write out the origin for the node
                writer.Write(subGrid.OriginX);
                writer.Write(subGrid.OriginY);

                subGrid.Write(writer);

                return true; // keep scanning
            }));
        }
コード例 #9
0
        /// <summary>
        /// Constructs a mask using polygonal and positional spatial filtering aspects of a filter.
        /// </summary>
        private static void ConstructSubGridSpatialAndPositionalMask(SubGridCellAddress currentSubGridOrigin,
                                                                     InterceptList intercepts,
                                                                     int fromProfileCellIndex,
                                                                     SubGridTreeBitmapSubGridBits mask,
                                                                     ICellSpatialFilter cellFilter,
                                                                     ISubGridTree subGridTree)
        {
            var cellFilterHasSpatialOrPositionalFilters = cellFilter.HasSpatialOrPositionalFilters;
            var interceptsCount = intercepts.Count;

            mask.Clear();

            for (var interceptIdx = fromProfileCellIndex; interceptIdx < interceptsCount; interceptIdx++)
            {
                // Determine the on-the-ground cell underneath the midpoint of each cell on the intercept line
                subGridTree.CalculateIndexOfCellContainingPosition(intercepts.Items[interceptIdx].MidPointX,
                                                                   intercepts.Items[interceptIdx].MidPointY, out var otgCellX, out var otgCellY);

                var thisSubGridOrigin = new SubGridCellAddress(otgCellX & ~SubGridTreeConsts.SubGridLocalKeyMask, otgCellY & ~SubGridTreeConsts.SubGridLocalKeyMask);

                if (!currentSubGridOrigin.Equals(thisSubGridOrigin))
                {
                    break;
                }

                var cellX = otgCellX & SubGridTreeConsts.SubGridLocalKeyMask;
                var cellY = otgCellY & SubGridTreeConsts.SubGridLocalKeyMask;

                if (cellFilterHasSpatialOrPositionalFilters)
                {
                    subGridTree.GetCellCenterPosition(otgCellX, otgCellY, out var cellCenterX, out var cellCenterY);

                    if (cellFilter.IsCellInSelection(cellCenterX, cellCenterY))
                    {
                        mask.SetBit(cellX, cellY);
                    }
                }
                else
                {
                    mask.SetBit(cellX, cellY);
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// Serializes the content of all the sub grids in the sub grid tree from the BinaryReader instance
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="reader"></param>
        /// <returns></returns>
        static bool SerialiseIn(ISubGridTree tree, BinaryReader reader)
        {
            tree.ID = reader.ReadGuid();

            // Read in the number of sub grids
            long SubGridCount = reader.ReadInt64();

            // Read in each sub grid and add it to the tree
            for (long I = 0; I < SubGridCount; I++)
            {
                // Read in the the origin for the node
                int OriginX = reader.ReadInt32();
                int OriginY = reader.ReadInt32();

                // Create a node to hold the bits
                ISubGrid SubGrid = tree.ConstructPathToCell(OriginX, OriginY, Types.SubGridPathConstructionType.CreateLeaf);
                SubGrid.Read(reader);
            }

            return(true);
        }
コード例 #11
0
        private static void ConstructSubGridSpatialAndPositionalMask(ISubGridTree tree,
                                                                     SubGridCellAddress currentSubGridOrigin,
                                                                     List <T> profileCells,
                                                                     SubGridTreeBitmapSubGridBits mask,
                                                                     int fromProfileCellIndex,
                                                                     ICellSpatialFilter cellFilter)
        {
            mask.Clear();

            // From current position to end...
            for (var cellIdx = fromProfileCellIndex; cellIdx < profileCells.Count; cellIdx++)
            {
                var profileCell       = profileCells[cellIdx];
                var thisSubGridOrigin = new SubGridCellAddress(
                    profileCell.OTGCellX & ~SubGridTreeConsts.SubGridLocalKeyMask,
                    profileCell.OTGCellY & ~SubGridTreeConsts.SubGridLocalKeyMask);

                if (!currentSubGridOrigin.Equals(thisSubGridOrigin))
                {
                    break;
                }

                var cellX = (byte)(profileCell.OTGCellX & SubGridTreeConsts.SubGridLocalKeyMask);
                var cellY = (byte)(profileCell.OTGCellY & SubGridTreeConsts.SubGridLocalKeyMask);

                if (cellFilter.HasSpatialOrPositionalFilters)
                {
                    tree.GetCellCenterPosition(profileCell.OTGCellX, profileCell.OTGCellY,
                                               out var cellCenterX, out var cellCenterY);
                    if (cellFilter.IsCellInSelection(cellCenterX, cellCenterY))
                    {
                        mask.SetBit(cellX, cellY);
                    }
                }
                else
                {
                    mask.SetBit(cellX, cellY);
                }
            }
        }
コード例 #12
0
        /// <summary>
        /// Provides Write() semantics for a sub grid tree against a BinaryWriter
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="header"></param>
        /// <param name="version"></param>
        /// <param name="writer"></param>
        /// <returns></returns>
        public static bool Write(ISubGridTree tree, string header, int version, BinaryWriter writer)
        {
            writer.Write(header);
            writer.Write(version);

            // Write place holder for stream size
            long SizePosition = writer.BaseStream.Position;

            writer.Write(0L);

            bool serializationResult = SerializeOut(tree, writer);

            if (serializationResult)
            {
                // Write the size of the stream in to the header
                long Size = writer.BaseStream.Position;
                writer.BaseStream.Seek(SizePosition, SeekOrigin.Begin);
                writer.Write(Size);
            }

            return(serializationResult);
        }
コード例 #13
0
        /// <summary>
        /// Construct either a node or a leaf sub grid for the given sub grid tree at the given level using the generic
        /// types Node and Leaf.
        /// </summary>
        /// <param name="tree"></param>
        /// <param name="treeLevel"></param>
        /// <returns>An ISubGrid interface representing the newly created node or leaf sub grid</returns>
        public virtual ISubGrid GetSubGrid(ISubGridTree tree, byte treeLevel)
        {
            // Ensure the requested tree level is valid for the given tree
            if (treeLevel < 1 || treeLevel > tree.NumLevels)
            {
                throw new ArgumentException($"Invalid treeLevel in sub grid factory: {treeLevel}, range is 1-{tree.NumLevels}", nameof(treeLevel));
            }

            if (treeLevel < tree.NumLevels)
            {
                return(new Node
                {
                    Owner = tree,
                    Level = treeLevel
                });
            }

            return(new Leaf
            {
                Owner = tree,
                Level = treeLevel
            });
        }
コード例 #14
0
 /// <summary>
 /// Base constructor for a Node type sub grid.
 /// </summary>
 public NodeSubGrid(ISubGridTree owner,
                    ISubGrid parent,
                    byte level) : base(owner, parent, level)
 {
     Initialise();
 }
コード例 #15
0
 /// <summary>
 /// Main constructor. Creates the local generic Items[,] array and delegates to base(...)
 /// </summary>
 /// <param name="owner"></param>
 /// <param name="parent"></param>
 /// <param name="level"></param>
 public GenericLeafSubGrid(ISubGridTree owner, ISubGrid parent, byte level) : base(owner, parent, level)
 {
     AllocateItems();
 }
コード例 #16
0
        public void ScanCellsOverTriangle(ISubGridTree tree,
                                          int triIndex,
                                          Func <ISubGridTree, int, int, bool> leafSatisfied,
                                          Action <ISubGridTree, int, int, int> includeTriangleInLeaf,
                                          Action <ISubGridTree,
                                                  int,                                  // sourceTriangle
                                                  Func <ISubGridTree, int, int, bool>,  // leafSatisfied
                                                  Action <ISubGridTree, int, int, int>, // includeTriangleInLeaf
                                                  XYZ, XYZ, XYZ, bool> ProcessTrianglePiece)
        {
            Triangle Tri = TriangleItems[triIndex];

            // Split triangle into two pieces, a 'top' piece and a 'bottom' piece to simplify
            // scanning across the triangle. Split is always with a horizontal line

            XYZ[] SortVertices = new XYZ[]
            {
                VertexItems[Tri.Vertex0],
                VertexItems[Tri.Vertex1],
                VertexItems[Tri.Vertex2]
            };

            if (SortVertices[0].Y > SortVertices[1].Y)
            {
                DesignGeometry.SwapVertices(ref SortVertices[0], ref SortVertices[1]);
            }
            if (SortVertices[1].Y > SortVertices[2].Y)
            {
                DesignGeometry.SwapVertices(ref SortVertices[1], ref SortVertices[2]);
            }
            if (SortVertices[0].Y > SortVertices[1].Y)
            {
                DesignGeometry.SwapVertices(ref SortVertices[0], ref SortVertices[1]);
            }

            XYZ TopVertex     = SortVertices[2];
            XYZ CentralVertex = SortVertices[1];
            XYZ BottomVertex  = SortVertices[0];

            // now make sure leftmost vertex in in first array item
            if (SortVertices[0].X > SortVertices[1].X)
            {
                DesignGeometry.SwapVertices(ref SortVertices[0], ref SortVertices[1]);
            }
            if (SortVertices[1].X > SortVertices[2].X)
            {
                DesignGeometry.SwapVertices(ref SortVertices[1], ref SortVertices[2]);
            }
            if (SortVertices[0].X > SortVertices[1].X)
            {
                DesignGeometry.SwapVertices(ref SortVertices[0], ref SortVertices[1]);
            }

            XYZ LeftMostVertex  = SortVertices[0];
            XYZ RightMostVertex = SortVertices[2];

            // Are top or bottom vertices coincident with the middle vertex
            bool BottomPieceOnly = Math.Abs(TopVertex.Y - CentralVertex.Y) < 0.0001;
            bool TopPieceOnly    = Math.Abs(BottomVertex.Y - CentralVertex.Y) < 0.0001;

            if (TopPieceOnly && BottomPieceOnly) // It's a thin horizontal triangle
            {
                ProcessTrianglePiece(tree, triIndex, leafSatisfied, includeTriangleInLeaf, LeftMostVertex, RightMostVertex, CentralVertex, true);
            }
            else
            {
                if (!(TopPieceOnly || BottomPieceOnly))
                {
                    // Divide triangle in two with a horizontal line
                    // Find intersection point of triangle edge between top most and bottom most vertices
                    if (LineIntersection.LinesIntersect(LeftMostVertex.X - 1, CentralVertex.Y,
                                                        RightMostVertex.X + 1, CentralVertex.Y,
                                                        TopVertex.X, TopVertex.Y,
                                                        BottomVertex.X, BottomVertex.Y,
                                                        out double IntersectX, out double IntersectY, true, out _))
                    {
                        XYZ IntersectionVertex = new XYZ(IntersectX, IntersectY, 0);
                        ProcessTrianglePiece(tree, triIndex, leafSatisfied, includeTriangleInLeaf, CentralVertex, IntersectionVertex, TopVertex, false);
                        ProcessTrianglePiece(tree, triIndex, leafSatisfied, includeTriangleInLeaf, CentralVertex, IntersectionVertex, BottomVertex, false);
                    }
                    else
                    {
                        Log.LogWarning($"Triangle {Tri} failed to have intersection line calculated for it");
                    }
                }
コード例 #17
0
 /// <summary>
 /// Overloaded Write() method that does not accept a header or version to include into the serialized
 /// stream. Header will be set to string.Empty and version will be set to 0.
 /// This should only be used in contexts where the existence of the stream is transient and never written
 /// to a persistent location that may be sensitive to version considerations.
 /// </summary>
 /// <param name="tree"></param>
 /// <param name="writer"></param>
 /// <returns></returns>
 public static bool Write(ISubGridTree tree, BinaryWriter writer) => Write(tree, string.Empty, 0, writer);
コード例 #18
0
 /// <summary>
 /// Main constructor. Creates the local generic Items[,] array and delegates to base(...)
 /// </summary>
 /// <param name="owner"></param>
 /// <param name="parent"></param>
 /// <param name="level"></param>
 /// <param name="cellSize"></param>
 /// <param name="indexOriginOffset"></param>
 protected GenericClientLeafSubGrid(ISubGridTree owner, ISubGrid parent, byte level, double cellSize, int indexOriginOffset) : base(owner, parent, level, cellSize, indexOriginOffset)
 {
 }
コード例 #19
0
 /// <summary>
 /// Constructor taking the tree reference, parent and level of the sub grid to be created
 /// </summary>
 public SubGridTreeLeafBitmapSubGrid(ISubGridTree owner,
                                     ISubGrid parent,
                                     byte level) : base(owner, parent, level)
 {
 }
コード例 #20
0
 /// <summary>
 /// Constructor. Set the grid to HeightAndTime.
 /// </summary>
 /// <param name="owner"></param>
 /// <param name="parent"></param>
 /// <param name="level"></param>
 /// <param name="cellSize"></param>
 /// <param name="indexOriginOffset"></param>
 public ClientHeightLeafSubGrid(ISubGridTree owner, ISubGrid parent, byte level, double cellSize, int indexOriginOffset) : base(owner, parent, level, cellSize, indexOriginOffset)
 {
     Initialise();
 }
コード例 #21
0
 public LeafSubGridBase(ISubGridTree owner,
                        ISubGrid parent,
                        byte level) : base(owner, parent, level)
 {
 }
コード例 #22
0
 /// <summary>
 /// Overloaded Read() method that does not accept a header or version to verify in the deserialized
 /// stream. Header will be expected to be string.Empty and version will be expected to be 0.
 /// This should only be used in contexts where the existence of the stream is transient and never read from
 /// a persistent location that may be sensitive to version considerations.
 /// </summary>
 /// <param name="tree"></param>
 /// <param name="reader"></param>
 /// <returns></returns>
 public static bool Read(ISubGridTree tree, BinaryReader reader) => Read(tree, string.Empty, 0, reader);