Exemplo n.º 1
0
        /// <summary>
        /// 中心地(経緯度)と東西軸方向・南北軸方向の距離(長さ次元)を含む矩形領域について
        /// DEMを切り出し・合成して取得する
        /// </summary>
        /// <remarks>
        /// 東西軸方向の臨界地点は赤道から遠い側(北半球なら北端における東西軸)が equatorial_delta を含む範囲で生成する。
        /// </remarks>
        /// <param name="delta">計算により採用された center からの経緯度差を out</param>
        /// <param name="z"></param>
        /// <param name="center"></param>
        /// <param name="equatorial_delta">中心地点から含めたい東西軸方向の距離</param>
        /// <param name="axial_delta">中心地点から含めたい南北軸方向の距離。 null の場合は equatorial_delta と同じ値とみなす</param>
        /// <param name="dem_type">対象とするDEM群</param>
        /// <returns>標高群</returns>
        public static double[,] LoadDEM
            (out ILonLatSettable delta
            , byte z
            , ILonLatGettable center
            , Length equatorial_delta
            , Length axial_delta = null
            , DEMType dem_type   = DEMType.DEM_5A_5B_10B
            )
        {
            axial_delta = axial_delta ?? equatorial_delta;

            // 南北方向の delta 地点へ center を射影した pa を得る
            var pa_angle = center.Latitude >= PlaneAngle.Zero ? PlaneAngle.Zero : PlaneAngle.FromTurns(0.5);
            var pa       = center.ProjectionTo(axial_delta, pa_angle);

            // 東西方向の delta 地点へ pa を射影した pae を得る
            var pae = pa.ProjectionTo(equatorial_delta, PlaneAngle.FromTurns(0.25));

            var d = pae - center;

            // out
            delta = d;

            return(LoadDEM(z, center, d, dem_type));
        }
Exemplo n.º 2
0
        /// <summary>
        /// 「標高タイル」をロード
        /// </summary>
        /// <param name="tile_location">タイル座標</param>
        /// <param name="dem_type">対象とするDEM群</param>
        /// <returns>標高群</returns>
        public static double[,] LoadDEM(TileLocation tile_location, DEMType dem_type = DEMType.DEM_5A_5B_10B)
        {
            if (tile_location.Z > 15)
            {
                return(null);
            }

            if
            (tile_location.Z == 15 &&
             !(dem_type.HasFlag(DEMType.DEM_5A) ||
               dem_type.HasFlag(DEMType.DEM_5B)
               )
            )
            {
                return(null);
            }

            double[,] r = null;

            const string ext = ".png";
            const double f   = 1.0e-2;

            if (tile_location.Z == 15)
            {
                if (dem_type.HasFlag(DEMType.DEM_5A))
                {
                    const string id  = "dem5a_png";
                    var          uri = new Uri($"{URIPatternBase}{id}/{tile_location.Z}/{tile_location.X}/{tile_location.Y}{ext}");

                    r = LoadPNGNumberTileS(out var has_invalid_value, uri, f, additional_invalid_values: DEMAdditionalInvalidValue);

                    if (!has_invalid_value)
                    {
                        return(r);
                    }
                }

                if (dem_type.HasFlag(DEMType.DEM_5B))
                {
                    const string id  = "dem5b_png";
                    var          uri = new Uri($"{URIPatternBase}{id}/{tile_location.Z}/{tile_location.X}/{tile_location.Y}{ext}");

                    bool has_invalid_value;

                    if (r == null)
                    {
                        r = LoadPNGNumberTileS(out has_invalid_value, uri, f, additional_invalid_values: DEMAdditionalInvalidValue);
                    }
                    else
                    {
                        LoadPNGNumberTileS(ref r, out has_invalid_value, uri, f, additional_invalid_values: DEMAdditionalInvalidValue);
                    }

                    if (!has_invalid_value)
                    {
                        return(r);
                    }
                }
            }

            if (dem_type.HasFlag(DEMType.DEM_10B))
            {
                const string id = "dem_png";

                // over-z
                if (tile_location.Z == 15)
                {
                    var zz  = 14;
                    var xx  = tile_location.X >> 1;
                    var yy  = tile_location.Y >> 1;
                    var uri = new Uri($"{URIPatternBase}{id}/{zz}/{xx}/{yy}{ext}");

                    using (var i = LoadPNGDataTile(uri))
                    {
                        // trimming
                        const int half    = ArrisLength >> 1;
                        var       trim_x0 = (tile_location.X & 1) == 1 ? half : 0;
                        var       trim_y0 = (tile_location.Y & 1) == 1 ? half : 0;
                        using (var trimmed = i.Clone(new Rectangle(trim_x0, trim_y0, half, half), i.PixelFormat))
                        {
                            // scaling
                            using (var scaled = new Bitmap(ArrisLength, ArrisLength))
                            {
                                using (var g = Graphics.FromImage(scaled))
                                {
                                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                                    g.DrawImage(trimmed, 0, 0, ArrisLength, ArrisLength);
                                }

                                bool has_invalid_value;

                                if (r == null)
                                {
                                    r = LoadPNGNumberTileS(out has_invalid_value, scaled, f, additional_invalid_values: DEMAdditionalInvalidValue);
                                }
                                else
                                {
                                    LoadPNGNumberTileS(ref r, out has_invalid_value, scaled, f, additional_invalid_values: DEMAdditionalInvalidValue);
                                }

                                if (!has_invalid_value)
                                {
                                    return(r);
                                }
                            }
                        }
                    }
                }
                else
                {
                    var uri = new Uri($"{URIPatternBase}{id}/{tile_location.Z}/{tile_location.X}/{tile_location.Y}{ext}");

                    r = LoadPNGNumberTileS(out var has_invalid_value, uri, f, additional_invalid_values: DEMAdditionalInvalidValue);

                    if (!has_invalid_value)
                    {
                        return(r);
                    }
                }
            }

            if (dem_type.HasFlag(DEMType.DEM_GM))
            {
                const string id         = "demgm_png";
                const byte   critical_z = 8;

                if (tile_location.Z > critical_z)
                {
                    var dz = tile_location.Z - critical_z;

                    var xx  = tile_location.X >> dz;
                    var yy  = tile_location.Y >> dz;
                    var uri = new Uri($"{URIPatternBase}{id}/{critical_z}/{xx}/{yy}{ext}");

                    using (var i = LoadPNGDataTile(uri))
                    {
                        // trimming
                        var scaled_length = ArrisLength >> dz;
                        var dx            = tile_location.X - (xx << dz);
                        var dy            = tile_location.Y - (yy << dz);
                        var trim_x0       = scaled_length * dx;
                        var trim_y0       = scaled_length * dy;
                        using (var trimmed = i.Clone(new Rectangle(( int )trim_x0, ( int )trim_y0, scaled_length, scaled_length), i.PixelFormat))
                        {
                            // scaling
                            using (var scaled = new Bitmap(ArrisLength, ArrisLength))
                            {
                                using (var g = Graphics.FromImage(scaled))
                                {
                                    g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
                                    g.DrawImage(trimmed, 0, 0, ArrisLength, ArrisLength);
                                }

                                bool has_invalid_value;

                                if (r == null)
                                {
                                    r = LoadPNGNumberTileS(out has_invalid_value, scaled, f, additional_invalid_values: DEMAdditionalInvalidValue);
                                }
                                else
                                {
                                    LoadPNGNumberTileS(ref r, out has_invalid_value, scaled, f, additional_invalid_values: DEMAdditionalInvalidValue);
                                }

                                if (!has_invalid_value)
                                {
                                    return(r);
                                }
                            }
                        }
                    }
                }
                else
                {
                    var uri = new Uri($"{URIPatternBase}{id}/{tile_location.Z}/{tile_location.X}/{tile_location.Y}{ext}");

                    if (r == null)
                    {
                        r = LoadPNGNumberTileS(out var has_invalid_value, uri, f, additional_invalid_values: DEMAdditionalInvalidValue);
                    }
                    else
                    {
                        LoadPNGNumberTileS(ref r, out var has_invalid_value, uri, f, additional_invalid_values: DEMAdditionalInvalidValue);
                    }
                }
            }

            return(r);
        }
Exemplo n.º 3
0
        /// <summary>
        /// 中心地(経緯度)と中心地からの範囲(経緯度差)による矩形領域について
        /// DEM を切り出し・合成して取得する
        /// </summary>
        /// <param name="z">Z</param>
        /// <param name="center">中心地</param>
        /// <param name="delta">中心地からの範囲(経緯度差)</param>
        /// <param name="dem_type">対象とするDEM群</param>
        /// <returns>標高群</returns>
        public static double[,] LoadDEM
            (byte z
            , ILonLatGettable center
            , ILonLatGettable delta
            , DEMType dem_type = DEMType.DEM_5A_5B_10B
            )
        {
            // 緯度軸方向の北端と南端を確定
            var dlatabs     = delta.Latitude.Abs();
            var north_angle = (center.Latitude + dlatabs).Normalize180();
            var south_angle = (center.Latitude - dlatabs).Normalize180();

            // 経度軸方向の西端と東端を確定
            var dlonabs    = delta.Longitude.Abs();
            var east_angle = (center.Longitude + dlonabs).Normalize360();
            var west_angle = (center.Longitude - dlonabs).Normalize360();

            //Console.WriteLine( $"e={east_angle}" );
            //Console.WriteLine( $"w={west_angle}" );
            //Console.WriteLine( $"n={north_angle}" );
            //Console.WriteLine( $"s={south_angle}" );

            // 東端・北端のピクセルを確定
            var north_east_pixel = WebMercator.AngleToPixel(new LonLat(east_angle, north_angle), z);
            // 西端・南端のピクセルを確定
            var south_west_pixel = WebMercator.AngleToPixel(new LonLat(west_angle, south_angle), z);

            //Console.WriteLine( $"N-E px = {north_east_pixel}" );
            //Console.WriteLine( $"S-W px = {south_west_pixel}" );

            // 東端・北端のタイルを確定
            var north_east_tile = WebMercator.PixelToTile(north_east_pixel);
            // 西端・南端のタイルを確定
            var south_west_tile = WebMercator.PixelToTile(south_west_pixel);

            //Console.WriteLine( $"N-E tile = {north_east_tile}" );
            //Console.WriteLine( $"S-W tile = {south_west_tile}" );

            // 最終的に必要なピクセル群のX軸サイズ; 区間 [ west ... east ] なのでサイズは +1
            // west < east
            var target_pixel_size_x = ( int )(north_east_pixel.X - south_west_pixel.X + 1);
            // 最終的に必要なピクセル群のY軸サイズ; 区間 [ north ... south ] なのでサイズは +1
            // north < south
            var target_pixel_size_y = ( int )(south_west_pixel.Y - north_east_pixel.Y + 1);

            // 出力用のバッファー
            var r = new double[target_pixel_size_x, target_pixel_size_y];

            // 北西から南東へ
            {
                // r 開始地点と data 開始地点のずれを計算
                const int tile_pixel_shift = 8;
                const int data_arris_size  = 1 << tile_pixel_shift;
                var       dpx = (int)(south_west_tile.X << tile_pixel_shift) - (int)south_west_pixel.X;
                var       dpy = (int)(north_east_tile.Y << tile_pixel_shift) - (int)north_east_pixel.Y;
                var       t   = new TileLocation(0, 0, z);
                // data ごとの r 開始位置を dp だけずらしておく
                var rx_begin = dpx;
                var ry_begin = dpy;
                for
                (t.Y = north_east_tile.Y
                 ; t.Y <= south_west_tile.Y
                 ; ++t.Y, ry_begin += data_arris_size, rx_begin = dpx
                )
                {
                    for
                    (t.X = south_west_tile.X
                     ; t.X <= north_east_tile.X
                     ; ++t.X, rx_begin += data_arris_size
                    )
                    {
                        // デコードして
                        var data = LoadDEM(t, dem_type);

                        //using ( var i = SavePNGNumberTileS( data, 1.0e-2, 0, Color.FromArgb( 255, 128, 0, 0 ) ) )
                        //  i.Save( System.IO.Path.Combine( System.Environment.GetFolderPath( System.Environment.SpecialFolder.DesktopDirectory ), $"GK/tmp/gyoe-{t.X}-{t.Y}-{t.Z}.png" ), System.Drawing.Imaging.ImageFormat.Png );

                        Func <int, int, double> sampler = (dx, dy) => data[dx, dy];
                        if (data == null)
                        {
                            sampler = (dx, dy) => double.NaN;
                        }

                        // r の適切な領域へ data をコピー
                        var rx = rx_begin;
                        var ry = ry_begin;
                        //Console.WriteLine( $"t={t} rx_begin={rx_begin} ry_begin={ry_begin}" );
                        for (var dy = 0; dy < data_arris_size; ++dy, ++ry, rx = rx_begin)
                        {
                            if (ry < 0 || ry >= r.GetLength(1))
                            {
                                continue;
                            }
                            else
                            {
                                for (var dx = 0; dx < data_arris_size; ++dx, ++rx)
                                {
                                    if (rx < 0 || rx >= r.GetLength(0))
                                    {
                                        continue;
                                    }
                                    else
                                    {
                                        //{
                                        r[rx, ry] = sampler(dx, dy);
                                    }
                                }
                            }
                        }
                        //Console.WriteLine( $"rx={rx} ry={ry} dx={dx} dy={dy} value={data[ dx, dy ]}" );
                        //}
                    }
                }
            }

            return(r);
        }