Exemplo n.º 1
0
        private void AddHeightMapBase(Triangulation triangulation, HeightMap heightMap, BoxBaseThickness thickness, float zValue)
        {
            // bake coordinates to avoid executing the coords transfrom pipeline
            var coords      = heightMap.Coordinates.ToList();
            int capacity    = heightMap.Width * 2 + (heightMap.Height - 2) * 2;
            var basePoints  = new List <GeoPoint>(capacity);
            var baseIndexes = new List <int>(capacity);

            float baseElevation = 0;

            switch (thickness)
            {
            case BoxBaseThickness.FromMinimumPoint:
                baseElevation = (float)coords.Min(p => p.Elevation).GetValueOrDefault(0) - zValue;
                break;

            default:
            case BoxBaseThickness.FixedElevation:
                baseElevation = zValue;
                break;
            }

            // x : 0 => width // y : 0
            int baseIndex0 = coords.Count;
            int baseIndex  = baseIndex0;

            for (int x = 0; x < heightMap.Width - 1; x++)
            {
                var pBase = coords[x].Clone();
                pBase.Elevation = baseElevation;
                basePoints.Add(pBase);

                baseIndexes.Add(x);
                baseIndexes.Add(baseIndex + 1);
                baseIndexes.Add(baseIndex);

                baseIndexes.Add(x + 1);
                baseIndexes.Add(baseIndex + 1);
                baseIndexes.Add(x);

                baseIndex++;
            }
            // x : width // y : 0 => height
            //
            for (int y = 0; y < heightMap.Height - 1; y++)
            {
                int x     = heightMap.Width - 1;
                int index = x + y * heightMap.Width;

                var pBase = coords[index].Clone();
                pBase.Elevation = baseElevation;
                basePoints.Add(pBase);

                baseIndexes.Add(x + y * heightMap.Width);
                baseIndexes.Add(baseIndex + 1);
                baseIndexes.Add(baseIndex);

                baseIndexes.Add(x + y * heightMap.Width);
                baseIndexes.Add(x + (y + 1) * heightMap.Width);
                baseIndexes.Add(baseIndex + 1);

                baseIndex++;
            }
            //// x : width => 0 // y : height
            for (int x = heightMap.Width - 1; x > 0; x--)
            {
                int index = x + (heightMap.Height - 1) * heightMap.Width;
                var pBase = coords[index].Clone();
                pBase.Elevation = baseElevation;
                basePoints.Add(pBase);

                baseIndexes.Add(index);
                baseIndexes.Add(index - 1);
                baseIndexes.Add(baseIndex);

                baseIndexes.Add(index - 1);
                baseIndexes.Add(baseIndex + 1);
                baseIndexes.Add(baseIndex);

                baseIndex++;
            }
            //// x : 0 // y : height => 0
            for (int y = heightMap.Height - 1; y > 0; y--)
            {
                int x     = 0;
                int index = x + y * heightMap.Width;

                var pBase = coords[index].Clone();
                pBase.Elevation = baseElevation;
                basePoints.Add(pBase);

                // last base position is the first base generated
                int nextBaseIndex = baseIndex + 1 > baseIndex0 + capacity - 1 ? baseIndex0 : baseIndex + 1;

                baseIndexes.Add(x + y * heightMap.Width);
                baseIndexes.Add(nextBaseIndex);
                baseIndexes.Add(baseIndex);

                baseIndexes.Add(x + y * heightMap.Width);
                baseIndexes.Add(x + (y - 1) * heightMap.Width);
                baseIndexes.Add(nextBaseIndex);


                baseIndex++;
            }


            // base (2 big triangles)
            baseIndexes.Add(baseIndex0);
            baseIndexes.Add(baseIndex0 + heightMap.Width - 1);
            baseIndexes.Add(baseIndex0 + heightMap.Width - 1 + heightMap.Height - 1);

            baseIndexes.Add(baseIndex0);
            baseIndexes.Add(baseIndex0 + heightMap.Width - 1 + heightMap.Height - 1);
            baseIndexes.Add(baseIndex0 + 2 * (heightMap.Width - 1) + heightMap.Height - 1);



            triangulation.Positions     = triangulation.Positions.Concat(basePoints);
            triangulation.NumPositions += basePoints.Count;
            triangulation.Indices       = triangulation.Indices.Concat(baseIndexes);
        }
Exemplo n.º 2
0
        public HeightMap GetHeightMapInBBox(BoundingBox bbox, FileMetadata metadata, float noDataValue = 0)
        {
            int yStart = 0;
            int yEnd   = 0;
            int xStart = 0;
            int xEnd   = 0;

            if (metadata.FileFormat.Registration == DEMFileRegistrationMode.Grid)
            {
                yStart = (int)Math.Floor((bbox.yMax - metadata.PhysicalEndLat) / metadata.pixelSizeY);
                yEnd   = (int)Math.Ceiling((bbox.yMin - metadata.PhysicalEndLat) / metadata.pixelSizeY);
                xStart = (int)Math.Floor((bbox.xMin - metadata.PhysicalStartLon) / metadata.pixelSizeX);
                xEnd   = (int)Math.Ceiling((bbox.xMax - metadata.PhysicalStartLon) / metadata.pixelSizeX);
            }
            else
            {
                yStart = (int)Math.Floor((bbox.yMax - metadata.DataEndLat) / metadata.pixelSizeY);
                yEnd   = (int)Math.Ceiling((bbox.yMin - metadata.DataEndLat) / metadata.pixelSizeY);
                xStart = (int)Math.Floor((bbox.xMin - metadata.DataStartLon) / metadata.pixelSizeX);
                xEnd   = (int)Math.Ceiling((bbox.xMax - metadata.DataStartLon) / metadata.pixelSizeX);
            }


            // Tiled geotiffs like aster have overlapping 1px borders
            int overlappingPixel = this.IsTiled ? 1 : 0;

            xStart = Math.Max(0, xStart);
            xEnd   = Math.Min(metadata.Width - 1, xEnd) - overlappingPixel;
            yStart = Math.Max(0, yStart);
            yEnd   = Math.Min(metadata.Height - 1, yEnd) - overlappingPixel;

            HeightMap heightMap = new HeightMap(xEnd - xStart + 1, yEnd - yStart + 1);

            heightMap.Count = heightMap.Width * heightMap.Height;
            var coords = new List <GeoPoint>(heightMap.Count);

            heightMap.BoundingBox = new BoundingBox(0, 0, 0, 0);

            if (this.IsTiled)
            {
                // Tiled rasters are composed of multiple "sub" images
                // TODO store in metadata
                int    tileWidth  = this.TileWidth;
                int    tileHeight = this.TileHeight;
                int    tileSize   = this.TileSize;
                byte[] buffer;

                for (int y = yStart; y <= yEnd; y++)
                {
                    double latitude = metadata.DataEndLat + (metadata.pixelSizeY * y);
                    // bounding box
                    if (y == yStart)
                    {
                        heightMap.BoundingBox.yMax = latitude;
                        heightMap.BoundingBox.xMin = metadata.DataStartLon + (metadata.pixelSizeX * xStart);
                        heightMap.BoundingBox.xMax = metadata.DataStartLon + (metadata.pixelSizeX * xEnd);
                    }
                    if (y == yEnd)
                    {
                        heightMap.BoundingBox.yMin = latitude;
                    }

                    for (int x = xStart; x <= xEnd; x++)
                    {
                        double longitude = metadata.DataStartLon + (metadata.pixelSizeX * x);
                        var    tileX     = (x / tileWidth) * tileWidth;
                        var    tileY     = (y / tileHeight) * tileHeight;

                        if (tilesCache == null)
                        {
                            tilesCache = new Dictionary <int, byte[]>();
                        }
                        var tileKey = (x / tileWidth) + (y / tileHeight) * (metadata.Width / tileWidth + 1);
                        if (!tilesCache.TryGetValue(tileKey, out buffer))
                        {
                            buffer = new byte[tileSize];
                            TiffFile.ReadTile(buffer, 0, tileX, tileY, 0, 0);
                            tilesCache.Add(tileKey, buffer);
                        }
                        var   offset      = x - tileX + (y - tileY) * tileHeight;
                        float heightValue = GetElevationAtPoint(metadata, offset, buffer);
                        if (heightValue <= 0)
                        {
                            heightMap.Minimum = Math.Min(heightMap.Minimum, heightValue);
                            heightMap.Maximum = Math.Max(heightMap.Maximum, heightValue);
                        }
                        else if (heightValue < 32768)
                        {
                            heightMap.Minimum = Math.Min(heightMap.Minimum, heightValue);
                            heightMap.Maximum = Math.Max(heightMap.Maximum, heightValue);
                        }

                        else
                        {
                            heightValue = (float)noDataValue;
                        }
                        coords.Add(new GeoPoint(latitude, longitude, heightValue));
                    }
                }
            }
            else
            {
                // metadata.BitsPerSample
                // When 16 we have 2 bytes per sample
                // When 32 we have 4 bytes per sample
                int    bytesPerSample = metadata.BitsPerSample / 8;
                byte[] byteScanline   = new byte[metadata.ScanlineSize];
                double endLat         = metadata.DataEndLat + metadata.pixelSizeY / 2d;
                double startLon       = metadata.DataStartLon + metadata.pixelSizeX / 2d;

                for (int y = yStart; y <= yEnd; y++)
                {
                    TiffFile.ReadScanline(byteScanline, y);

                    // TODO: handle Cell registered DEMs: lat is 1/2 pixel off
                    double latitude = endLat + (metadata.pixelSizeY * y);

                    // bounding box
                    if (y == yStart)
                    {
                        heightMap.BoundingBox.yMax = latitude;
                        heightMap.BoundingBox.xMin = startLon + (metadata.pixelSizeX * xStart);
                        heightMap.BoundingBox.xMax = startLon + (metadata.pixelSizeX * xEnd);
                    }
                    else if (y == yEnd)
                    {
                        heightMap.BoundingBox.yMin = latitude;
                    }

                    for (int x = xStart; x <= xEnd; x++)
                    {
                        double longitude = startLon + (metadata.pixelSizeX * x);

                        float heightValue = 0;
                        switch (metadata.SampleFormat)
                        {
                        case RasterSampleFormat.FLOATING_POINT:
                            heightValue = BitConverter.ToSingle(byteScanline, x * bytesPerSample);
                            break;

                        case RasterSampleFormat.INTEGER:
                            heightValue = BitConverter.ToInt16(byteScanline, x * bytesPerSample);
                            break;

                        case RasterSampleFormat.UNSIGNED_INTEGER:
                            heightValue = BitConverter.ToUInt16(byteScanline, x * bytesPerSample);
                            break;

                        default:
                            throw new Exception("Sample format unsupported.");
                        }
                        if (heightValue <= 0)
                        {
                            heightMap.Minimum = Math.Min(heightMap.Minimum, heightValue);
                            heightMap.Maximum = Math.Max(heightMap.Maximum, heightValue);
                        }
                        else if (heightValue < 32768)
                        {
                            heightMap.Minimum = Math.Min(heightMap.Minimum, heightValue);
                            heightMap.Maximum = Math.Max(heightMap.Maximum, heightValue);
                        }

                        else
                        {
                            heightValue = (float)noDataValue;
                        }
                        coords.Add(new GeoPoint(latitude, longitude, heightValue));
                    }
                }
            }
            Debug.Assert(heightMap.Width * heightMap.Height == coords.Count);

            heightMap.Coordinates = coords;
            return(heightMap);
        }
Exemplo n.º 3
0
        public HeightMap GetHeightMap(FileMetadata metadata)
        {
            if (this.isTiled)
            {
                throw new NotImplementedException("Whole height map with tile geoTiff is not implemented");
            }

            HeightMap heightMap = new HeightMap(metadata.Width, metadata.Height);

            heightMap.Count = heightMap.Width * heightMap.Height;
            var coords = new List <GeoPoint>(heightMap.Count);

            // metadata.BitsPerSample
            // When 16 we have 2 bytes per sample
            // When 32 we have 4 bytes per sample
            int bytesPerSample = metadata.BitsPerSample / 8;

            byte[] byteScanline = new byte[metadata.ScanlineSize];

            for (int y = 0; y < metadata.Height; y++)
            {
                TiffFile.ReadScanline(byteScanline, y);

                double latitude = metadata.DataStartLat + (metadata.pixelSizeY * y);
                for (int x = 0; x < metadata.Width; x++)
                {
                    double longitude = metadata.DataStartLon + (metadata.pixelSizeX * x);

                    float heightValue = 0;
                    switch (metadata.SampleFormat)
                    {
                    case RasterSampleFormat.FLOATING_POINT:
                        heightValue = BitConverter.ToSingle(byteScanline, x * metadata.BitsPerSample / 8);
                        break;

                    case RasterSampleFormat.INTEGER:
                        heightValue = BitConverter.ToInt16(byteScanline, x * metadata.BitsPerSample / 8);
                        break;

                    case RasterSampleFormat.UNSIGNED_INTEGER:
                        heightValue = BitConverter.ToUInt16(byteScanline, x * metadata.BitsPerSample / 8);
                        break;

                    default:
                        throw new Exception("Sample format unsupported.");
                    }
                    if (heightValue < 32768)
                    {
                        heightMap.Minimum = Math.Min(metadata.MinimumAltitude, heightValue);
                        heightMap.Maximum = Math.Max(metadata.MaximumAltitude, heightValue);
                    }
                    else
                    {
                        heightValue = 0;
                    }
                    coords.Add(new GeoPoint(latitude, longitude, heightValue));
                }
            }

            heightMap.Coordinates = coords;
            return(heightMap);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Sort height map coordinates (lat descending, then lon)
        /// </summary>
        /// <param name="heightMap"></param>
        /// <returns></returns>
        public static HeightMap Sort(this HeightMap heightMap)
        {
            heightMap.Coordinates = heightMap.Coordinates.Sort();

            return(heightMap);
        }
Exemplo n.º 5
0
 /// <summary>
 /// Rescale the height map in order that it fits into the specified size
 /// </summary>
 /// <param name="heightMap"></param>
 /// <param name="maxSize"></param>
 /// <returns></returns>
 public static HeightMap FitInto(this HeightMap heightMap, float maxSize)
 {
     return(FitInto(heightMap, maxSize, out float scale));
 }
Exemplo n.º 6
0
        /// <summary>
        /// Helper to get an in memory coordinate list
        /// useful to generate normal maps and let the same height map follow the pipeline (reproj, center, ...)
        /// </summary>
        /// <returns></returns>
        public static HeightMap BakeCoordinates(this HeightMap heightMap)
        {
            heightMap.Coordinates = heightMap.Coordinates.ToList();

            return(heightMap);
        }
Exemplo n.º 7
0
        public HeightMap GetHeightMapInBBox(BoundingBox bbox, FileMetadata metadata, float noDataValue = 0)
        {
            // metadata.BitsPerSample
            // When 16 we have 2 bytes per sample
            // When 32 we have 4 bytes per sample
            int bytesPerSample = metadata.BitsPerSample / 8;

            byte[] byteScanline = new byte[metadata.ScanlineSize];


            int yStart = (int)Math.Floor((bbox.yMax - metadata.StartLat) / metadata.pixelSizeY);
            int yEnd   = (int)Math.Ceiling((bbox.yMin - metadata.StartLat) / metadata.pixelSizeY);
            int xStart = (int)Math.Floor((bbox.xMin - metadata.StartLon) / metadata.pixelSizeX);
            int xEnd   = (int)Math.Ceiling((bbox.xMax - metadata.StartLon) / metadata.pixelSizeX);

            xStart = Math.Max(0, xStart);
            xEnd   = Math.Min(metadata.Width - 1, xEnd);
            yStart = Math.Max(0, yStart);
            yEnd   = Math.Min(metadata.Height - 1, yEnd);

            HeightMap heightMap = new HeightMap(xEnd - xStart + 1, yEnd - yStart + 1);

            heightMap.Count = heightMap.Width * heightMap.Height;
            var coords = new List <GeoPoint>(heightMap.Count);

            heightMap.BoundingBox = new BoundingBox(0, 0, 0, 0);

            for (int y = yStart; y <= yEnd; y++)
            {
                TiffFile.ReadScanline(byteScanline, y);

                double latitude = metadata.StartLat + (metadata.pixelSizeY * y);

                // bounding box
                if (y == yStart)
                {
                    heightMap.BoundingBox.yMax = latitude;
                    heightMap.BoundingBox.xMin = metadata.StartLon + (metadata.pixelSizeX * xStart);
                    heightMap.BoundingBox.xMax = metadata.StartLon + (metadata.pixelSizeX * xEnd);
                }
                else if (y == yEnd)
                {
                    heightMap.BoundingBox.yMin = latitude;
                }

                for (int x = xStart; x <= xEnd; x++)
                {
                    double longitude = metadata.StartLon + (metadata.pixelSizeX * x);

                    float heightValue = 0;
                    switch (metadata.SampleFormat)
                    {
                    case RasterSampleFormat.FLOATING_POINT:
                        heightValue = BitConverter.ToSingle(byteScanline, x * bytesPerSample);
                        break;

                    case RasterSampleFormat.INTEGER:
                        heightValue = BitConverter.ToInt16(byteScanline, x * bytesPerSample);
                        break;

                    case RasterSampleFormat.UNSIGNED_INTEGER:
                        heightValue = BitConverter.ToUInt16(byteScanline, x * bytesPerSample);
                        break;

                    default:
                        throw new Exception("Sample format unsupported.");
                    }
                    if (heightValue <= 0)
                    {
                        heightMap.Minimum = Math.Min(heightMap.Minimum, heightValue);
                        heightMap.Maximum = Math.Max(heightMap.Maximum, heightValue);
                    }
                    else if (heightValue < 32768)
                    {
                        heightMap.Minimum = Math.Min(heightMap.Minimum, heightValue);
                        heightMap.Maximum = Math.Max(heightMap.Maximum, heightValue);
                    }

                    else
                    {
                        heightValue = (float)noDataValue;
                    }
                    coords.Add(new GeoPoint(latitude, longitude, heightValue));
                }
            }
            Debug.Assert(heightMap.Width * heightMap.Height == coords.Count);

            heightMap.Coordinates = coords;
            return(heightMap);
        }
Exemplo n.º 8
0
        public HeightMap GetHeightMap(FileMetadata metadata)
        {
            HeightMap heightMap = new HeightMap(metadata.Width, metadata.Height);

            heightMap.Count = heightMap.Width * heightMap.Height;
            var coords = new List <GeoPoint>(heightMap.Count);

            _hgtStream.Seek(0, SeekOrigin.Begin);

            // metadata.BitsPerSample
            // When 16 we have 2 bytes per sample
            // When 32 we have 4 bytes per sample
            int bytesPerSample = metadata.BitsPerSample / 8;

            byte[] byteScanline = new byte[metadata.ScanlineSize];

            for (int y = 0; y < metadata.Height; y++)
            {
                _hgtStream.Read(byteScanline, 0, metadata.ScanlineSize);

                double latitude = metadata.StartLat + (metadata.pixelSizeY * y);
                for (int x = 0; x < metadata.Width; x++)
                {
                    double longitude = metadata.StartLon + (metadata.pixelSizeX * x);

                    float  heightValue = 0;
                    byte[] heightBytes = new byte[bytesPerSample];;
                    if (BitConverter.IsLittleEndian)
                    {
                        // reverse bytes
                        for (int i = 0; i < bytesPerSample; i++)
                        {
                            heightBytes[i] = byteScanline[x * bytesPerSample + bytesPerSample - i - 1];
                        }
                        switch (metadata.SampleFormat)
                        {
                        case RasterSampleFormat.FLOATING_POINT:
                            heightValue = BitConverter.ToSingle(heightBytes, 0);
                            break;

                        case RasterSampleFormat.INTEGER:
                            heightValue = BitConverter.ToInt16(heightBytes, 0);
                            break;

                        case RasterSampleFormat.UNSIGNED_INTEGER:
                            heightValue = BitConverter.ToUInt16(heightBytes, 0);
                            break;

                        default:
                            throw new Exception("Sample format unsupported.");
                        }
                    }
                    else
                    {
                        switch (metadata.SampleFormat)
                        {
                        case RasterSampleFormat.FLOATING_POINT:
                            heightValue = BitConverter.ToSingle(byteScanline, x * bytesPerSample);
                            break;

                        case RasterSampleFormat.INTEGER:
                            heightValue = BitConverter.ToInt16(byteScanline, x * bytesPerSample);
                            break;

                        case RasterSampleFormat.UNSIGNED_INTEGER:
                            heightValue = BitConverter.ToUInt16(byteScanline, x * bytesPerSample);
                            break;

                        default:
                            throw new Exception("Sample format unsupported.");
                        }
                    }
                    if (heightValue < 32768)
                    {
                        heightMap.Minimum = Math.Min(metadata.MinimumAltitude, heightValue);
                        heightMap.Maximum = Math.Max(metadata.MaximumAltitude, heightValue);
                    }
                    else
                    {
                        heightValue = 0;
                    }
                    coords.Add(new GeoPoint(latitude, longitude, heightValue));
                }
            }

            heightMap.Coordinates = coords;
            return(heightMap);
        }