コード例 #1
0
        private static double YToGeoTiffPixelY(M.RasterProperties rasterProperties, double y)
        {
            if (rasterProperties.ProjectedBounds == null)
            {
                throw new ArgumentNullException(nameof(rasterProperties), "rasterProperties.ProjectedBounds is null.");
            }

            return((rasterProperties.ProjectedBounds.Top - y) / rasterProperties.PixelHeight);
        }
コード例 #2
0
        private static double XToGeoTiffPixelX(M.RasterProperties rasterProperties, double x)
        {
            if (rasterProperties.ProjectedBounds == null)
            {
                throw new ArgumentNullException(nameof(rasterProperties), "rasterProperties.ProjectedBounds is null.");
            }

            return((x - rasterProperties.ProjectedBounds.Left) / rasterProperties.PixelWidth);
        }
コード例 #3
0
        private static GeoTiff.TileCoordinates GetGeoTiffTileCoordinatesAtPoint(
            M.RasterProperties rasterProperties,
            double x,
            double y)
        {
            var tileX = (int)Math.Floor(XToGeoTiffPixelX(rasterProperties, x) / (double)rasterProperties.TileWidth);
            var tileY = (int)Math.Floor(YToGeoTiffPixelY(rasterProperties, y) / (double)rasterProperties.TileHeight);

            return(new GeoTiff.TileCoordinates(tileX, tileY));
        }
コード例 #4
0
        private static List <GeoTiff.TileCoordinates> BuildTileCoordinatesList(
            M.RasterProperties rasterProperties,
            M.Bounds bounds)
        {
            if (rasterProperties == null)
            {
                throw new ArgumentNullException(nameof(rasterProperties));
            }

            if (rasterProperties.ProjectedBounds == null)
            {
                throw new ArgumentException("ProjectedBounds property is null.");
            }

            var tileCoordMin = GetGeoTiffTileCoordinatesAtPoint(
                rasterProperties,
                Math.Max(bounds.Left, rasterProperties.ProjectedBounds.Left),
                Math.Min(bounds.Top, rasterProperties.ProjectedBounds.Top));

            var tileCoordMax = GetGeoTiffTileCoordinatesAtPoint(
                rasterProperties,
                Math.Min(bounds.Right, rasterProperties.ProjectedBounds.Right),
                Math.Min(bounds.Bottom, rasterProperties.ProjectedBounds.Bottom));

            var tileCoordinates = new List <GeoTiff.TileCoordinates>();

            for (var tileX = tileCoordMin.X; tileX <= tileCoordMax.X; tileX++)
            {
                for (var tileY = tileCoordMin.Y; tileY <= tileCoordMax.Y; tileY++)
                {
                    tileCoordinates.Add(new GeoTiff.TileCoordinates(tileX, tileY));
                }
            }

            return(tileCoordinates);
        }
コード例 #5
0
        private static M.RasterProperties ReadGeoTiffProperties(string path)
        {
            using var tiff = Tiff.Open(path, ModeOpenReadTiff);

            var planarConfig = (PlanarConfig)tiff.GetField(TiffTag.PLANARCONFIG)[0].ToInt();

            if (planarConfig != PlanarConfig.CONTIG)
            {
                throw new FormatException($"Only single image plane storage organization ({PlanarConfig.CONTIG}) is supported");
            }

            if (!tiff.IsTiled())
            {
                throw new FormatException($"Only tiled storage scheme is supported");
            }

            var imageWidth  = tiff.GetField(TiffTag.IMAGEWIDTH)[0].ToInt();
            var imageHeight = tiff.GetField(TiffTag.IMAGELENGTH)[0].ToInt();

            var tileWidth  = tiff.GetField(TiffTag.TILEWIDTH)[0].ToInt();
            var tileHeight = tiff.GetField(TiffTag.TILELENGTH)[0].ToInt();

            // ModelPixelScale  https://freeimage.sourceforge.io/fnet/html/CC586183.htm
            var modelPixelScale = tiff.GetField(TiffTag.GEOTIFF_MODELPIXELSCALETAG);
            var pixelSizesCount = modelPixelScale[0].ToInt();
            var pixelSizes      = modelPixelScale[1].ToDoubleArray();

            // ModelTiePoints  https://freeimage.sourceforge.io/fnet/html/38F9430A.htm
            var tiePointTag    = tiff.GetField(TiffTag.GEOTIFF_MODELTIEPOINTTAG);
            var tiePointsCount = tiePointTag[0].ToInt();
            var tiePoints      = tiePointTag[1].ToDoubleArray();

            if ((tiePoints.Length != 6) || (tiePoints[0] != 0) || (tiePoints[1] != 0) || (tiePoints[2] != 0) || (tiePoints[5] != 0))
            {
                throw new FormatException($"Only single tie point is supported"); // TODO: Only simple tie points scheme is supported
            }

            var modelTransformation = tiff.GetField(TiffTag.GEOTIFF_MODELTRANSFORMATIONTAG);

            if (modelTransformation != null)
            {
                throw new FormatException($"Only simple projection without transformation is supported");
            }

            var srId = 0;

            // Simple check SRS of GeoTIFF tie points
            var geoKeys = tiff.GetField(TiffTag.GEOTIFF_GEOKEYDIRECTORYTAG);

            if (geoKeys != null)
            {
                var geoDoubleParams = tiff.GetField(TiffTag.GEOTIFF_GEODOUBLEPARAMSTAG);
                double[]? doubleParams = null;
                if (geoDoubleParams != null)
                {
                    doubleParams = geoDoubleParams[1].ToDoubleArray();
                }

                var geoAsciiParams = tiff.GetField(TiffTag.GEOTIFF_GEOASCIIPARAMSTAG);

                // Array of GeoTIFF GeoKeys values
                var keys = geoKeys[1].ToUShortArray();
                if (keys.Length > 4)
                {
                    // Header={KeyDirectoryVersion, KeyRevision, MinorRevision, NumberOfKeys}
                    var keyDirectoryVersion = keys[0];
                    var keyRevision         = keys[1];
                    var minorRevision       = keys[2];
                    var numberOfKeys        = keys[3];
                    for (var keyIndex = 4; keyIndex < keys.Length;)
                    {
                        switch (keys[keyIndex])
                        {
                        case (ushort)GeoTiff.Key.GTModelTypeGeoKey:
                        {
                            var modelType = (GeoTiff.ModelType)keys[keyIndex + 3];
                            if (!((modelType == GeoTiff.ModelType.Projected) || (modelType == GeoTiff.ModelType.Geographic)))
                            {
                                throw new FormatException("Only coordinate systems ModelTypeProjected (1) or ModelTypeGeographic (2) are supported");
                            }

                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GTRasterTypeGeoKey:
                        {
                            var rasterType = (GeoTiff.RasterType)keys[keyIndex + 3];         // TODO: use RasterTypeCode value
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GTCitationGeoKey:
                        {
                            var gtc = keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeographicTypeGeoKey:
                        {
                            var geographicType = keys[keyIndex + 3];
                            if (geographicType != 4326)
                            {
                                throw new FormatException("Only EPSG:4326 geodetic coordinate system is supported");
                            }

                            srId      = geographicType;
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogCitationGeoKey:
                        {
                            var geogCitation = keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogGeodeticDatumGeoKey:
                        {
                            // 6.3.2.2 Geodetic Datum Codes
                            var geodeticDatum = keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogPrimeMeridianGeoKey:
                        {
                            // 6.3.2.4 Prime Meridian Codes
                            var primeMeridian = keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogAngularUnitsGeoKey:
                        {
                            var geogAngularUnit = (GeoTiff.AngularUnits)keys[keyIndex + 3];
                            if (geogAngularUnit != GeoTiff.AngularUnits.Degree)
                            {
                                throw new FormatException("Only degree angular unit is supported");
                            }

                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogAngularUnitSizeGeoKey:
                        {
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogEllipsoidGeoKey:
                        {
                            // 6.3.2.3 Ellipsoid Codes
                            var geogEllipsoid = keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogSemiMajorAxisGeoKey:
                        {
                            if (doubleParams == null)
                            {
                                throw new FormatException($"Double values were not found in '{TiffTag.GEOTIFF_GEODOUBLEPARAMSTAG}' tag");
                            }

                            var geogSemiMajorAxis = doubleParams[keys[keyIndex + 3]];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogSemiMinorAxisGeoKey:
                        {
                            if (doubleParams == null)
                            {
                                throw new FormatException($"Double values were not found in '{TiffTag.GEOTIFF_GEODOUBLEPARAMSTAG}' tag");
                            }

                            var geogSemiMinorAxis = doubleParams[keys[keyIndex + 3]];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogInvFlatteningGeoKey:
                        {
                            if (doubleParams == null)
                            {
                                throw new FormatException($"Double values were not found in '{TiffTag.GEOTIFF_GEODOUBLEPARAMSTAG}' tag");
                            }

                            var geogInvFlattening = doubleParams[keys[keyIndex + 3]];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogAzimuthUnitsGeoKey:
                        {
                            // 6.3.1.4 Angular Units Codes
                            var geogAzimuthUnits = (GeoTiff.AngularUnits)keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.GeogPrimeMeridianLongGeoKey:
                        {
                            var geogPrimeMeridianLong = keys[keyIndex + 3];
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.ProjectedCSTypeGeoKey:
                        {
                            var projectedCSType = keys[keyIndex + 3];
                            if (projectedCSType != 3857)
                            {
                                throw new FormatException($"Only EPSG:3857 projected coordinate system is supported (input was: {projectedCSType})");
                            }

                            // TODO: UTM (EPSG:32636 and others) support
                            srId      = projectedCSType;
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.PCSCitationGeoKey:
                        {
                            keyIndex += 4;
                            break;
                        }

                        case (ushort)GeoTiff.Key.ProjLinearUnitsGeoKey:
                        {
                            var linearUnit = (GeoTiff.LinearUnits)keys[keyIndex + 3];
                            if (linearUnit != GeoTiff.LinearUnits.Meter)
                            {
                                throw new FormatException("Only meter linear unit is supported");
                            }

                            keyIndex += 4;
                            break;
                        }

                        default:
                        {
                            keyIndex += 4;         // Just skipping all unprocessed keys
                            break;
                        }
                        }
                    }
                }
            }

            M.GeographicalBounds?geographicalBounds = null;
            M.Bounds?            projectedBounds = null;
            double pixelWidth = 0.0, pixelHeight = 0.0;

            switch (srId)
            {
            case 4326:     // TODO: const
                {
                    geographicalBounds = new M.GeographicalBounds(
                        tiePoints[3],
                        tiePoints[4] - imageHeight * pixelSizes[1],
                        tiePoints[3] + imageWidth * pixelSizes[0],
                        tiePoints[4]);

                    projectedBounds = new M.Bounds(
                        U.WebMercator.X(tiePoints[3]),
                        U.WebMercator.Y(tiePoints[4] - imageHeight * pixelSizes[1]),
                        U.WebMercator.X(tiePoints[3] + imageWidth * pixelSizes[0]),
                        U.WebMercator.Y(tiePoints[4]));

                    pixelWidth  = U.WebMercator.X(tiePoints[3] + pixelSizes[0]) - U.WebMercator.X(tiePoints[3]);
                    pixelHeight = U.WebMercator.Y(tiePoints[4]) - U.WebMercator.Y(tiePoints[4] - pixelSizes[1]);

                    break;
                }

            case 3857:     // TODO: const
            {
                projectedBounds = new M.Bounds(
                    tiePoints[3],
                    tiePoints[4] - imageHeight * pixelSizes[1],
                    tiePoints[3] + imageWidth * pixelSizes[0],
                    tiePoints[4]);

                geographicalBounds = new M.GeographicalBounds(
                    U.WebMercator.Longitude(tiePoints[3]),
                    U.WebMercator.Latitude(tiePoints[4] - imageHeight * pixelSizes[1]),
                    U.WebMercator.Longitude(tiePoints[3] + imageWidth * pixelSizes[0]),
                    U.WebMercator.Latitude(tiePoints[4]));

                pixelWidth  = pixelSizes[0];
                pixelHeight = pixelSizes[1];

                break;
            }

            default:
            {
                throw new InvalidOperationException($"SRID '{srId}' is not supported");
            }
            }

            var result = new M.RasterProperties
            {
                Srid               = srId,
                ImageWidth         = imageWidth,
                ImageHeight        = imageHeight,
                TileWidth          = tileWidth,
                TileHeight         = tileHeight,
                TileSize           = tiff.TileSize(),
                ProjectedBounds    = projectedBounds,
                GeographicalBounds = geographicalBounds,
                PixelWidth         = pixelWidth,
                PixelHeight        = pixelHeight,
            };

            return(result);
        }