Ejemplo n.º 1
0
        private System.Windows.Shapes.Rectangle CreateTileRectangle(PointCloudTile tile, FrameworkElement image, Panel grid)
        {
            double containerWidth  = image.ActualWidth;
            double containerHeight = image.ActualHeight;

            double imageLocationX = (grid.ActualWidth - containerWidth) / 2;
            double imageLocationY = (grid.ActualHeight - containerHeight) / 2;

            double tileRatioX = (double)tile.Col / (CurrentTileSource.TileSet.Cols);
            double tileRatioY = 1 - ((double)(tile.Row + 1) / (CurrentTileSource.TileSet.Rows));

            double tileLocationX = imageLocationX + tileRatioX * containerWidth;
            double tileLocationY = imageLocationY + tileRatioY * containerHeight;

            double tileRatioWidth  = 1.0 / (CurrentTileSource.TileSet.Cols);
            double tileRatioHeight = 1.0 / (CurrentTileSource.TileSet.Rows);

            System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle();

            rect.StrokeThickness = 1;
            rect.Stroke          = System.Windows.Media.Brushes.Green;

            rect.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
            rect.VerticalAlignment   = System.Windows.VerticalAlignment.Top;

            rect.Width  = tileRatioWidth * containerWidth;
            rect.Height = tileRatioHeight * containerHeight;

            rect.Margin = new Thickness(tileLocationX, tileLocationY, 0, 0);

            return(rect);
        }
Ejemplo n.º 2
0
        private void SortByDistanceFromTile(PointCloudTile[] tiles, PointCloudTile centerTile)
        {
            float[] distanceToCenter2 = new float[tiles.Length];
            for (int i = 0; i < tiles.Length; i++)
            {
                distanceToCenter2[i] = (float)(Math.Pow(tiles[i].Col - centerTile.Col, 2) + Math.Pow(tiles[i].Row - centerTile.Row, 2));
            }

            Array.Sort(distanceToCenter2, tiles);
        }
Ejemplo n.º 3
0
        public int Decompress(PointCloudTile tile, byte[] compressedBuffer, int count, byte[] uncompressedBuffer)
        {
            MemoryStream uncompressedStream = new MemoryStream(uncompressedBuffer);
            MemoryStream compressedStream   = new MemoryStream(compressedBuffer, 0, count, false);

            using (SevenZipExtractor extractor = new SevenZipExtractor(compressedStream))
            {
                extractor.ExtractFile(0, uncompressedStream);
            }

            return((int)uncompressedStream.Position);
        }
Ejemplo n.º 4
0
        public int Decompress(PointCloudTile tile, byte[] compressedBuffer, int count, byte[] uncompressedBuffer)
        {
            MemoryStream compressedStream = new MemoryStream(compressedBuffer, 0, count, false);

            int uncompressedBytes = 0;

            using (ZipInputStream zipStream = new ZipInputStream(compressedStream, true))
            {
                zipStream.GetNextEntry();
                uncompressedBytes = zipStream.Read(uncompressedBuffer, 0, uncompressedBuffer.Length);
            }

            return(uncompressedBytes);
        }
Ejemplo n.º 5
0
        public TileInfo3D(PointCloudTile tile, GeometryModel3D lowResGeometry, Grid <float> lowResGrid)
        {
            Tile = tile;

            LowResGeometry = lowResGeometry;
            LowResGrid     = lowResGrid;

            m_currentGeometry = LowResGeometry;
            m_currentGrid     = LowResGrid;

            m_stitchingHasChanged = false;

            m_stitchingGeometry = new GeometryModel3D[3];
            m_stitchingGrid     = new Grid <float> [3];
        }
Ejemplo n.º 6
0
        public int Compress(PointCloudTile tile, byte[] uncompressedBuffer, int count, byte[] compressedBuffer)
        {
            MemorableMemoryStream compressedStream = new MemorableMemoryStream(compressedBuffer);

            using (ZipOutputStream zipStream = new ZipOutputStream(compressedStream, true))
            {
                zipStream.CompressionMethod = Ionic.Zip.CompressionMethod.Deflate;
                zipStream.CompressionLevel  = Ionic.Zlib.CompressionLevel.BestSpeed;

                zipStream.PutNextEntry("a");
                zipStream.Write(uncompressedBuffer, 0, count);
            }

            return((int)compressedStream.MaxPosition);
        }
Ejemplo n.º 7
0
        public int Compress(PointCloudTile tile, byte[] uncompressedBuffer, int count, byte[] compressedBuffer)
        {
            SevenZipCompressor compressor = new SevenZipCompressor
            {
                CompressionMethod = SevenZip.CompressionMethod.Lzma2,
                CompressionLevel  = CompressionLevel.Fast
            };

            MemoryStream uncompressedStream = new MemoryStream(uncompressedBuffer, 0, count, false);

            // custom stream is required because the position is always 32 instead of the end of the stream
            MemorableMemoryStream compressedStream = new MemorableMemoryStream(compressedBuffer);

            compressor.CompressStream(uncompressedStream, compressedStream);

            return((int)compressedStream.MaxPosition);
        }
Ejemplo n.º 8
0
        private void UpdateCurrentTile(PointCloudTile tile)
        {
            foreach (System.Windows.Shapes.Rectangle rect in m_loadedTiles.Values)
            {
                rect.Stroke = System.Windows.Media.Brushes.DarkGray;
            }

            if (tile == null)
            {
                return;
            }

            var tilesToLoad = new List <PointCloudTile>();
            //int pointsToLoad = 0;

            int radius = 4;

            int xMin = Math.Max(0, tile.Col - radius);
            int xMax = Math.Min(tile.Col + radius + 1, CurrentTileSource.TileSet.Cols);
            int yMin = Math.Max(0, tile.Row - radius);
            int yMax = Math.Min(tile.Row + radius + 1, CurrentTileSource.TileSet.Rows);

            for (int x = xMin; x < xMax; x++)
            {
                for (int y = yMin; y < yMax; y++)
                {
                    PointCloudTile currentTile = CurrentTileSource.TileSet.GetTile(y, x);

                    if (currentTile != null)
                    {
                        if (!m_loadedTiles.ContainsKey(currentTile))
                        {
                            tilesToLoad.Add(currentTile);
                            //pointsToLoad += currentTile.PointCount;

                            System.Windows.Shapes.Rectangle rect = CreateTileRectangle(currentTile, previewImage, previewImageGrid);
                            m_loadedTiles.Add(currentTile, rect);

                            previewImageGraphicsGrid.Children.Add(rect);
                        }
                        else
                        {
                            System.Windows.Shapes.Rectangle rect = m_loadedTiles[currentTile];
                            if (tile.Equals(currentTile))
                            {
                                rect.Stroke = System.Windows.Media.Brushes.Red;
                            }
                            else
                            {
                                rect.Stroke = System.Windows.Media.Brushes.Blue;
                            }
                        }
                    }
                }
            }

            PointCloudTile[] loadedTiles = m_loadedTiles.Keys.ToArray();
            SortByDistanceFromTile(loadedTiles, tile);
            Array.Reverse(loadedTiles);

            // drop loaded tiles that are the farthest from the center
            int totalAllowedPoints = MAX_BUFFER_SIZE_BYTES / CurrentTileSource.PointSizeBytes;
            int loadedPoints       = loadedTiles.Sum(t => t.PointCount);

            int potentialTotalPoints = loadedPoints;            // +pointsToLoad;

            if (potentialTotalPoints > totalAllowedPoints)
            {
                int pointsToDrop = potentialTotalPoints - totalAllowedPoints;
                int i            = 0;
                while (pointsToDrop > 0 && i < loadedTiles.Length)
                {
                    PointCloudTile currentTile           = loadedTiles[i];
                    System.Windows.Shapes.Rectangle rect = m_loadedTiles[currentTile];
                    m_loadedTiles.Remove(currentTile);
                    m_loadedTileBuffers.Remove(currentTile);

                    // I don't know why I need to do this, but I can occasionally get a duplicate add below if I don't
                    tilesToLoad.Remove(currentTile);

                    previewImageGraphicsGrid.Children.Remove(rect);
                    pointsToDrop -= currentTile.PointCount;
                    ++i;
                }
            }

            var tilesToLoadOrdered = CurrentTileSource.TileSet.GetTileReadOrder(tilesToLoad);

            foreach (PointCloudTile currentTile in tilesToLoadOrdered)
            {
                // this will cause fragmentation problems, but it's just for demonstration
                byte[] inputBuffer = new byte[currentTile.PointCount * CurrentTileSource.PointSizeBytes];
                CurrentTileSource.LoadTile(currentTile, inputBuffer);
                m_loadedTileBuffers.Add(currentTile, inputBuffer);
            }
        }
Ejemplo n.º 9
0
        void IWriter.Save(int fileIndex)
        {
            int skippedCounter = 0;

            string fileOnly   = Path.GetFileNameWithoutExtension(importSettings.outputFile);
            string baseFolder = Path.GetDirectoryName(importSettings.outputFile);

            Console.ForegroundColor = ConsoleColor.Blue;
            Console.WriteLine("Saving " + nodeX.Count + " tiles to folder: " + baseFolder);
            Console.ForegroundColor = ConsoleColor.White;

            List <float> nodeTempX;
            List <float> nodeTempY;
            List <float> nodeTempZ;
            List <float> nodeTempR;
            List <float> nodeTempG;
            List <float> nodeTempB;

            // process all tiles
            foreach (KeyValuePair <string, List <float> > nodeData in nodeX)
            {
                if (nodeData.Value.Count < importSettings.minimumPointCount)
                {
                    skippedCounter++;
                    continue;
                }

                nodeTempX = nodeData.Value;
                nodeTempY = nodeY[nodeData.Key];
                nodeTempZ = nodeZ[nodeData.Key];
                nodeTempR = nodeR[nodeData.Key];
                nodeTempG = nodeG[nodeData.Key];
                nodeTempB = nodeB[nodeData.Key];

                // randomize points in this node
                if (importSettings.randomize == true)
                {
                    Tools.Shuffle(Tools.rnd, ref nodeTempX, ref nodeTempY, ref nodeTempZ, ref nodeTempR, ref nodeTempG, ref nodeTempB);
                }

                // get this node bounds, TODO but we know node(grid cell) x,y,z values?
                float minX = float.PositiveInfinity;
                float minY = float.PositiveInfinity;
                float minZ = float.PositiveInfinity;
                float maxX = float.NegativeInfinity;
                float maxY = float.NegativeInfinity;
                float maxZ = float.NegativeInfinity;

                // build tilefile for points in this node
                string fullpath         = Path.Combine(baseFolder, fileOnly) + "_" + fileIndex + "_" + nodeData.Key + tileExtension;
                string fullpathFileOnly = fileOnly + "_" + fileIndex + "_" + nodeData.Key + tileExtension;

                // if batch mode (more than 1 file), FIXME generates new unique filename..but why not overwrite?
                if (fileIndex > 0 && File.Exists(fullpath))
                {
                    //Console.WriteLine("File already exists! " + fullpath);
                    Int32 unixTimestamp = (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds;
                    fullpath         = Path.Combine(baseFolder, fileOnly) + "_" + fileIndex + "_" + nodeData.Key + "_r" + (unixTimestamp) + tileExtension;
                    fullpathFileOnly = fileOnly + "_" + fileIndex + "_" + nodeData.Key + tileExtension;
                }

                // prepare file
                bsPoints     = new BufferedStream(new FileStream(fullpath, FileMode.Create));
                writerPoints = new BinaryWriter(bsPoints);

                int cellX = 0;
                int cellY = 0;
                int cellZ = 0;

                // FIXME this is wrong value, if file is appended.. but for now append is disabled
                int totalPointsWritten = 0;

                // output all points within that node tile
                for (int i = 0, len = nodeTempX.Count; i < len; i++)
                {
                    // skip points
                    if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0))
                    {
                        continue;
                    }

                    // keep points
                    if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0))
                    {
                        continue;
                    }

                    float px = nodeTempX[i];
                    float py = nodeTempY[i];
                    float pz = nodeTempZ[i];

                    // FIXME bounds is wrong if appended (but append is disabled now), should include previous data also, but now append is disabled.. also probably should use known cell xyz bounds directly
                    if (px < minX)
                    {
                        minX = px;
                    }
                    if (px > maxX)
                    {
                        maxX = px;
                    }
                    if (py < minY)
                    {
                        minY = py;
                    }
                    if (py > maxY)
                    {
                        maxY = py;
                    }
                    if (pz < minZ)
                    {
                        minZ = pz;
                    }
                    if (pz > maxZ)
                    {
                        maxZ = pz;
                    }

                    if (importSettings.packColors == true)
                    {
                        float pxx = px;

                        // get local coords within tile
                        var keys = nodeData.Key.Split('_');
                        // TODO no need to parse, we should know these values?
                        cellX = int.Parse(keys[0]);
                        cellY = int.Parse(keys[1]);
                        cellZ = int.Parse(keys[2]);
                        px   -= (cellX * importSettings.gridSize);
                        py   -= (cellY * importSettings.gridSize);
                        pz   -= (cellZ * importSettings.gridSize);

                        // pack red and x
                        px = Tools.SuperPacker(nodeTempR[i] * 0.98f, px, importSettings.gridSize * importSettings.packMagicValue);
                        // pack green and y
                        py = Tools.SuperPacker(nodeTempG[i] * 0.98f, py, importSettings.gridSize * importSettings.packMagicValue);
                        // pack blue and z
                        pz = Tools.SuperPacker(nodeTempB[i] * 0.98f, pz, importSettings.gridSize * importSettings.packMagicValue);
                    }

                    writerPoints.Write(px);
                    writerPoints.Write(py);
                    writerPoints.Write(pz);

                    totalPointsWritten++;
                } // loop all points in tile (node)

                // close tile file
                writerPoints.Close();
                bsPoints.Dispose();

                if (importSettings.packColors == false)
                {
                    // save separate RGB
                    BufferedStream bsColors;

                    bsColors = new BufferedStream(new FileStream(fullpath + ".rgb", FileMode.Create));
                    var writerColors = new BinaryWriter(bsColors);

                    // output all points within that node cell
                    for (int i = 0, len = nodeTempX.Count; i < len; i++)
                    {
                        // skip points
                        if (importSettings.skipPoints == true && (i % importSettings.skipEveryN == 0))
                        {
                            continue;
                        }

                        // keep points
                        if (importSettings.keepPoints == true && (i % importSettings.keepEveryN != 0))
                        {
                            continue;
                        }

                        //if (i < 1000) Console.WriteLine(nodeTempR[i] + ", " + nodeTempG[i] + ", " + nodeTempB[i]);

                        writerColors.Write(nodeTempR[i]);
                        writerColors.Write(nodeTempG[i]);
                        writerColors.Write(nodeTempB[i]);
                    } // loop all point in cell cells

                    // close tile/node
                    writerColors.Close();
                    bsColors.Dispose();
                }

                // collect node bounds, name and pointcount
                var cb = new PointCloudTile();
                cb.fileName = fullpathFileOnly;
                //cb.totalPoints = nodeTempX.Count;
                cb.totalPoints = totalPointsWritten;

                // get bounds and cell XYZ
                cb.minX    = minX;
                cb.minY    = minY;
                cb.minZ    = minZ;
                cb.maxX    = maxX;
                cb.maxY    = maxY;
                cb.maxZ    = maxZ;
                cb.centerX = (minX + maxX) * 0.5f;
                cb.centerY = (minY + maxY) * 0.5f;
                cb.centerZ = (minZ + maxZ) * 0.5f;
                cb.cellX   = cellX;
                cb.cellY   = cellY;
                cb.cellZ   = cellZ;

                nodeBounds.Add(cb);
            } // loop all nodes

            // save rootfile
            // only save after last file, TODO should save this if process fails or user cancels, so no need to start from 0 again.. but then needs some merge or continue from index n feature
            if (fileIndex == (importSettings.maxFiles - 1))
            {
                var tilerootdata   = new List <string>();
                var outputFileRoot = Path.Combine(baseFolder, fileOnly) + ".pcroot";

                // add to tileroot list
                long totalPointCount = 0;
                for (int i = 0, len = nodeBounds.Count; i < len; i++)
                {
                    var tilerow = nodeBounds[i].fileName + sep + nodeBounds[i].totalPoints + sep + nodeBounds[i].minX + sep + nodeBounds[i].minY + sep + nodeBounds[i].minZ + sep + nodeBounds[i].maxX + sep + nodeBounds[i].maxY + sep + nodeBounds[i].maxZ + sep + nodeBounds[i].cellX + sep + nodeBounds[i].cellY + sep + nodeBounds[i].cellZ;
                    tilerootdata.Add(tilerow);
                    totalPointCount += nodeBounds[i].totalPoints;
                }

                Console.WriteLine("\nSaving rootfile: " + outputFileRoot + "\n*Total points= " + Tools.HumanReadableCount(totalPointCount));

                int versionID = importSettings.packColors ? 2 : 1; // (1 = original, 2 = packed v3 format)
                if (importSettings.packColors == true)
                {
                    versionID = 2;
                }

                // add global header settings to first row
                //               version,          gridsize,                   pointcount,             boundsMinX,       boundsMinY,       boundsMinZ,       boundsMaxX,       boundsMaxY,       boundsMaxZ
                var globalData = versionID + sep + importSettings.gridSize.ToString() + sep + totalPointCount + sep + cloudMinX + sep + cloudMinY + sep + cloudMinZ + sep + cloudMaxX + sep + cloudMaxY + sep + cloudMaxZ;
                //                  autoOffsetX,             globalOffsetY,           globalOffsetZ,           packMagic
                globalData += sep + importSettings.offsetX + sep + importSettings.offsetY + sep + importSettings.offsetZ + sep + importSettings.packMagicValue;

                tilerootdata.Insert(0, globalData);

                File.WriteAllLines(outputFileRoot, tilerootdata.ToArray());

                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine("Done saving v3 : " + outputFileRoot);
                Console.ForegroundColor = ConsoleColor.White;
                if (skippedCounter > 0)
                {
                    Console.WriteLine("*Skipped " + skippedCounter + " nodes with less than " + importSettings.minimumPointCount + " points)");
                }

                if ((tilerootdata.Count - 1) <= 0)
                {
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine("Error> No tiles found! Try enable -scale (to make your cloud to smaller) Or make -gridsize bigger, or set -limit point count to smaller value");
                    Console.ForegroundColor = ConsoleColor.White;
                }
            }
        }
Ejemplo n.º 10
0
        private void UpdateCurrentTile(PointCloudTile tile)
        {
            if (tile == null)
            {
                return;
            }

            List <PointCloudTile> tilesToLoad = new List <PointCloudTile>();
            int pointsToLoad = 0;

            Model3DGroup emptyModelGroup = new Model3DGroup();

            emptyModelGroup.Freeze();

            bool isDirty = false;

            int radius = 2;

            int xMin = Math.Max(0, tile.Col - radius);
            int xMax = Math.Min(tile.Col + radius + 1, CurrentTileSource.TileSet.Cols);
            int yMin = Math.Max(0, tile.Row - radius);
            int yMax = Math.Min(tile.Row + radius + 1, CurrentTileSource.TileSet.Rows);

            for (int x = xMin; x < xMax; x++)
            {
                for (int y = yMin; y < yMax; y++)
                {
                    PointCloudTile currentTile = CurrentTileSource.TileSet.GetTile(y, x);

                    if (currentTile != null)
                    {
                        if (!m_loadedTiles.ContainsKey(currentTile))
                        {
                            tilesToLoad.Add(currentTile);
                            pointsToLoad += currentTile.PointCount;

                            isDirty = true;
                        }
                    }
                }
            }

            PointCloudTile[] loadedTiles = m_loadedTiles.Keys.ToArray();
            SortByDistanceFromTile(loadedTiles, tile);
            Array.Reverse(loadedTiles);

            // drop loaded tiles that are the farthest from the center
            int totalAllowedPoints = MAX_BUFFER_SIZE_BYTES / CurrentTileSource.PointSizeBytes;
            int loadedPoints       = loadedTiles.Sum(t => t.PointCount);

            int potentialTotalPoints = loadedPoints + pointsToLoad;

            Dictionary <PointCloudTile, TileInfo3D> alteredTiles = new Dictionary <PointCloudTile, TileInfo3D>();

            if (potentialTotalPoints > totalAllowedPoints)
            {
                int pointsToDrop = potentialTotalPoints - totalAllowedPoints;
                int i            = 0;
                while (pointsToDrop > 0)
                {
                    PointCloudTile  currentTile = loadedTiles[i];
                    TileInfo3D      tileInfo    = m_tileInfo[currentTile];
                    GeometryModel3D model       = m_loadedTiles[currentTile];

                    m_meshTileMap.Remove(model);
                    m_loadedTiles.Remove(currentTile);
                    //m_loadedTileBuffers.Remove(currentTile);

                    // replace high-res tile with low-res geometry
                    int modelIndex = tileInfo.Tile.ValidIndex;
                    m_tileModelCollection[modelIndex] = tileInfo.LowResGeometry;
                    // clear stitching
                    m_stitchingModelCollection[modelIndex] = emptyModelGroup;
                    tileInfo.ClearGeometry();

                    alteredTiles.Add(currentTile, tileInfo);

                    pointsToDrop -= currentTile.PointCount;
                    ++i;
                }
            }

            Jacere.Core.Geometry.Point3D centerOfMass = CurrentTileSource.CenterOfMass;

            PointCloudTile[] tilesToLoadArray = tilesToLoad.ToArray();
#warning sort so that disk reads are in order? or make a tile cache
            SortByDistanceFromTile(tilesToLoadArray, tile);
            foreach (PointCloudTile currentTile in tilesToLoadArray)
            {
                TileInfo3D tileInfo = m_tileInfo[currentTile];
                CurrentTileSource.LoadTileGrid(currentTile, m_buffer, m_gridHighRes, m_quantizedGridHighRes);
                if (ENABLE_HEIGHT_EXAGGERATION)
                {
                    m_gridHighRes.Multiply(m_heightExaggerationFactor, (float)centerOfMass.Z);
                }

                Jacere.Core.Geometry.Extent3D tileExtent = currentTile.Extent;
                MeshGeometry3D mesh = CurrentTileSource.GenerateMesh(m_gridHighRes, tileExtent);

                DiffuseMaterial material = new DiffuseMaterial();
                if (USE_HIGH_RES_TEXTURE)
                {
                    material.Brush          = m_overviewTextureBrush;
                    mesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(mesh, m_overallCenteredExtent, MathUtils.ZAxis);
                }
                else
                {
                    material.Brush = m_solidBrush;
                }

                material.Freeze();
                GeometryModel3D geometryModel = new GeometryModel3D(mesh, material);
                geometryModel.Freeze();

                // replace low-res tile with high-res geometry
                int modelIndex = tileInfo.Tile.ValidIndex;
                m_tileModelCollection[modelIndex] = geometryModel;
                // clear stitching
                m_stitchingModelCollection[modelIndex] = emptyModelGroup;
                tileInfo.UpdateGeometry(geometryModel, m_gridHighRes);

                alteredTiles.Add(currentTile, tileInfo);

                m_meshTileMap.Add(geometryModel, currentTile);
                m_loadedTiles.Add(currentTile, geometryModel);
                //m_loadedTileBuffers.Add(currentTile, inputBuffer);
            }

            // in the future, I could have a list of which tiles need to be checked for stitching updates


            // go through the stitching groups and replace any empty ones with the appropriate stitching
            if (ENABLE_STITCHING && isDirty)
            {
                PointCloudTile[] alteredTileArray = alteredTiles.Keys.ToArray();
                foreach (PointCloudTile currentTile in alteredTileArray)
                {
                    // this amount of clearing is excessive.  I only want to clear one of the edges

                    if (currentTile.Col < CurrentTileSource.TileSet.Cols - 1)
                    {
                        PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row, currentTile.Col + 1);
                        if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile))
                        {
                            TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile];
                            if (!alteredTiles.ContainsKey(adjacentTile))
                            {
                                alteredTiles.Add(adjacentTile, adjacentTileInfo);
                            }

                            m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup;
                            adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.Left);
                        }
                    }

                    if (currentTile.Row < CurrentTileSource.TileSet.Rows - 1)
                    {
                        PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row + 1, currentTile.Col);
                        if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile))
                        {
                            TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile];
                            if (!alteredTiles.ContainsKey(adjacentTile))
                            {
                                alteredTiles.Add(adjacentTile, adjacentTileInfo);
                            }

                            m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup;
                            adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.Top);
                        }
                    }

                    if (currentTile.Col < CurrentTileSource.TileSet.Cols - 1 && currentTile.Row < CurrentTileSource.TileSet.Rows - 1)
                    {
                        PointCloudTile adjacentTile = CurrentTileSource.TileSet.GetTile(currentTile.Row + 1, currentTile.Col + 1);
                        if (adjacentTile != null && m_tileInfo.ContainsKey(adjacentTile))
                        {
                            TileInfo3D adjacentTileInfo = m_tileInfo[adjacentTile];
                            if (!alteredTiles.ContainsKey(adjacentTile))
                            {
                                alteredTiles.Add(adjacentTile, adjacentTileInfo);
                            }

                            m_stitchingModelCollection[adjacentTileInfo.Tile.ValidIndex] = emptyModelGroup;
                            adjacentTileInfo.UpdateStitching(null, null, TileStitchingEdge.TopLeft);
                        }
                    }
                }

                foreach (KeyValuePair <PointCloudTile, TileInfo3D> kvp in alteredTiles)
                {
                    int          i = kvp.Value.Tile.ValidIndex;
                    Model3DGroup stitchingGroup = m_stitchingModelCollection[i] as Model3DGroup;
                    if (stitchingGroup.Children.Count == 0)
                    {
                        GeometryModel3D geometryModel     = m_tileModelCollection[i] as GeometryModel3D;
                        Model3DGroup    newStitchingGroup = GenerateTileStitching(CurrentTileSource, kvp.Value);
                        if (newStitchingGroup.Children.Count > 0)
                        {
                            m_stitchingModelCollection[i] = newStitchingGroup;
                        }
                    }
                }

                //for (int i = 0; i < m_stitchingModelCollection.Count; i++)
                //{
                //    Model3DGroup stitchingGroup = m_stitchingModelCollection[i] as Model3DGroup;
                //    // this is an incorrect condition, but it won't be apparent until I get multi-res stitching
                //    if (stitchingGroup.Children.Count < 3)
                //    {
                //        GeometryModel3D geometryModel = m_tileModelCollection[i] as GeometryModel3D;
                //        PointCloudTile currentTile = m_meshTileMap[geometryModel];
                //        TileInfo3D currentTileInfo = m_tileInfo[currentTile];
                //        Model3DGroup newStitchingGroup = GenerateTileStitching(CurrentTileSource, currentTileInfo);
                //        if (newStitchingGroup.Children.Count > 0)
                //            m_stitchingModelCollection[i] = newStitchingGroup;
                //    }
                //}
            }
        }
Ejemplo n.º 11
0
        private Model3DGroup GenerateTileStitching(PointCloudTileSource tileSource, TileInfo3D tileInfo)
        {
            PointCloudTile tile = tileInfo.Tile;
            MeshGeometry3D mesh = GetTileMeshGeometry(tileInfo.CurrentGeometry);
            Grid <float>   grid = tileInfo.CurrentGrid;

            //Model3DGroup stitchingGroup = new Model3DGroup();

            bool hasTop  = false;
            bool hasLeft = false;

            Point3D topCornerPoint  = default(Point3D);
            Point3D leftCornerPoint = default(Point3D);

            Vector3D topCornerNormal  = default(Vector3D);
            Vector3D leftCornerNormal = default(Vector3D);

            // connect to left tile (if available)
            if (tile.Col > 0)
            {
                PointCloudTile leftTile     = tileSource.TileSet.GetTile(tile.Row, tile.Col - 1);
                TileInfo3D     leftTileInfo = null;
                if (leftTile != null && m_tileInfo.TryGetValue(leftTile, out leftTileInfo) && leftTileInfo.CurrentGrid == grid)
                {
                    MeshGeometry3D leftMesh           = GetTileMeshGeometry(leftTileInfo.CurrentGeometry);
                    int            leftPositionsStart = leftMesh.Positions.Count - grid.SizeY;

                    hasLeft          = true;
                    leftCornerPoint  = leftMesh.Positions[leftPositionsStart];
                    leftCornerNormal = leftMesh.Normals[leftPositionsStart];

                    if (!tileInfo.HasStitching(TileStitchingEdge.Left))
                    {
                        MeshGeometry3D stitchingMesh = new MeshGeometry3D();

                        int positionCount            = grid.SizeY * 2;
                        Point3DCollection  positions = new Point3DCollection(positionCount);
                        Vector3DCollection normals   = new Vector3DCollection(positionCount);

                        for (int edgePosition = 0; edgePosition < grid.SizeY; edgePosition++)
                        {
                            positions.Add(leftMesh.Positions[leftPositionsStart + edgePosition]);
                            normals.Add(leftMesh.Normals[leftPositionsStart + edgePosition]);

                            positions.Add(mesh.Positions[edgePosition]);
                            normals.Add(mesh.Normals[edgePosition]);
                        }
                        stitchingMesh.Positions = positions;
                        stitchingMesh.Normals   = normals;

                        Int32Collection indices = new Int32Collection((grid.SizeY - 1) * 6);
                        for (int i = 0; i < grid.SizeY - 1; i++)
                        {
                            int j = 2 * i;
                            indices.Add(j);
                            indices.Add(j + 1);
                            indices.Add(j + 2);

                            indices.Add(j + 2);
                            indices.Add(j + 1);
                            indices.Add(j + 3);
                        }
                        stitchingMesh.TriangleIndices = indices;

                        stitchingMesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(stitchingMesh, m_overallCenteredExtent, MathUtils.ZAxis);

                        GeometryModel3D stitchingModel = new GeometryModel3D(stitchingMesh, m_overviewMaterial);
                        stitchingModel.Freeze();

                        tileInfo.UpdateStitching(stitchingModel, leftTileInfo.CurrentGrid, TileStitchingEdge.Left);
                        //stitchingGroup.Children.Add(stitchingModel);
                    }
                }
            }

            // connect to top tile (if available)
            if (tile.Row > 0)
            {
                PointCloudTile topTile     = tileSource.TileSet.GetTile(tile.Row - 1, tile.Col);
                TileInfo3D     topTileInfo = null;
                if (topTile != null && m_tileInfo.TryGetValue(topTile, out topTileInfo) && topTileInfo.CurrentGrid == grid)
                {
                    MeshGeometry3D topMesh = GetTileMeshGeometry(topTileInfo.CurrentGeometry);

                    hasTop          = true;
                    topCornerPoint  = topMesh.Positions[grid.SizeY - 1];
                    topCornerNormal = topMesh.Normals[grid.SizeY - 1];

                    if (!tileInfo.HasStitching(TileStitchingEdge.Top))
                    {
                        MeshGeometry3D stitchingMesh = new MeshGeometry3D();

                        int positionCount            = grid.SizeX * 2;
                        Point3DCollection  positions = new Point3DCollection(positionCount);
                        Vector3DCollection normals   = new Vector3DCollection(positionCount);

                        for (int edgePosition = 0; edgePosition < mesh.Positions.Count; edgePosition += grid.SizeY)
                        {
                            positions.Add(topMesh.Positions[edgePosition + grid.SizeY - 1]);
                            normals.Add(topMesh.Normals[edgePosition + grid.SizeY - 1]);

                            positions.Add(mesh.Positions[edgePosition]);
                            normals.Add(mesh.Normals[edgePosition]);
                        }
                        stitchingMesh.Positions = positions;
                        stitchingMesh.Normals   = normals;

                        Int32Collection indices = new Int32Collection((grid.SizeX - 1) * 6);
                        for (int i = 0; i < grid.SizeX - 1; i++)
                        {
                            int j = 2 * i;

                            indices.Add(j);
                            indices.Add(j + 2);
                            indices.Add(j + 1);

                            indices.Add(j + 2);
                            indices.Add(j + 3);
                            indices.Add(j + 1);
                        }
                        stitchingMesh.TriangleIndices = indices;

                        stitchingMesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(stitchingMesh, m_overallCenteredExtent, MathUtils.ZAxis);

                        GeometryModel3D stitchingModel = new GeometryModel3D(stitchingMesh, m_overviewMaterial);
                        stitchingModel.Freeze();

                        tileInfo.UpdateStitching(stitchingModel, topTileInfo.CurrentGrid, TileStitchingEdge.Top);
                        //stitchingGroup.Children.Add(stitchingModel);
                    }
                }
            }

            // connect to top left tile (if available)
            if (hasTop && hasLeft && !tileInfo.HasStitching(TileStitchingEdge.TopLeft))
            {
                PointCloudTile topleftTile     = tileSource.TileSet.GetTile(tile.Row - 1, tile.Col - 1);
                TileInfo3D     topleftTileInfo = null;
                if (topleftTile != null && m_tileInfo.TryGetValue(topleftTile, out topleftTileInfo))
                {
                    MeshGeometry3D topleftMesh   = GetTileMeshGeometry(topleftTileInfo.CurrentGeometry);
                    MeshGeometry3D stitchingMesh = new MeshGeometry3D();

                    Point3DCollection  positions = new Point3DCollection(4);
                    Vector3DCollection normals   = new Vector3DCollection(4);
                    {
                        positions.Add(topleftMesh.Positions[topleftMesh.Positions.Count - 1]);
                        normals.Add(topleftMesh.Normals[topleftMesh.Positions.Count - 1]);

                        positions.Add(topCornerPoint);
                        normals.Add(topCornerNormal);

                        positions.Add(leftCornerPoint);
                        normals.Add(leftCornerNormal);

                        positions.Add(mesh.Positions[0]);
                        normals.Add(mesh.Normals[0]);
                    }
                    stitchingMesh.Positions = positions;
                    stitchingMesh.Normals   = normals;

                    Int32Collection indices = new Int32Collection(6);
                    indices.Add(0);
                    indices.Add(1);
                    indices.Add(2);
                    indices.Add(2);
                    indices.Add(1);
                    indices.Add(3);
                    stitchingMesh.TriangleIndices = indices;

                    stitchingMesh.TextureCoordinates = MeshUtils.GeneratePlanarTextureCoordinates(stitchingMesh, m_overallCenteredExtent, MathUtils.ZAxis);

                    GeometryModel3D stitchingModel = new GeometryModel3D(stitchingMesh, m_overviewMaterial);
                    stitchingModel.Freeze();

                    tileInfo.UpdateStitching(stitchingModel, topleftTileInfo.CurrentGrid, TileStitchingEdge.TopLeft);
                    //stitchingGroup.Children.Add(stitchingModel);
                }
            }

            return(tileInfo.GetNewStitching());
        }