简体   繁体   中英

Postgresql function to C#

I'm trying to calculate the given tile a node is in from OpenStreetMap so that I can manually add nodes directly into the current_nodes table. If I want to add a new node at latitude X and longitude Y, I can then calculate the 'tile' value that's needed before inserting into the current_nodes table.

I'm trying to convert the current PostgreSQL function into C# but it's not giving the output expected. I'm not sure I've converted it correctly or if I'm missing something.

//maptile_for_point(scaled_lat bigint, scaled_lon bigint, zoom integer)
DECLARE
  lat CONSTANT DOUBLE PRECISION := scaled_lat / 10000000.0;
  lon CONSTANT DOUBLE PRECISION := scaled_lon / 10000000.0;
  zscale CONSTANT DOUBLE PRECISION := 2.0 ^ zoom;
  pi CONSTANT DOUBLE PRECISION := 3.141592653589793;
  r_per_d CONSTANT DOUBLE PRECISION := pi / 180.0;
  x int4;
  y int4;
BEGIN
  -- straight port of the C code. see db/functions/maptile.c
  x := floor((lon + 180.0) * zscale / 360.0);
  y := floor((1.0 - ln(tan(lat * r_per_d) + 1.0 / cos(lat * r_per_d)) / pi) * zscale / 2.0);

  RETURN (x << zoom) | y;
END;

So far I have:

 public const double pi = 3.141592653589793;
 public const double r_per_d = pi / 180.0;    

 public static long GetTile(double scaled_lat, double scaled_lon, int zoom)
 {
     double lat = scaled_lat / 10000000.0;
     double lon = scaled_lon / 10000000.0;
     return GetTile(lat, lon, zoom);
 }

 public static long GetTile(long lat, long lon, int zoom)
 {
     double zscale = Math.Pow(2.0, zoom);
     long x = (long)Math.Floor((lon + 180.0) * zscale / 360.0);
     long y = (long)Math.Floor((1.0 - Math.Log(Math.Tan(lat * r_per_d) + 1.0 / Math.Cos(lat * r_per_d)) / pi) * zscale / 2.0);
     return (x << zoom) | y;
 }

I call the function but loop through possible zoom values but none of them are matching the expected output.

Using data that's already in the table (526868344, -18000386) it should return 2062343892.

for (int i = 0; i < int.MaxValue; i++)
{
    var r1 = NodeTileHelper.GetTile(526868344, -18000386, i);
    if (r1 == 2062343892)
    {
        ;
    }
}

It looks like the problem might be how the method overloads are defined.

The following snippet of code is going to call the GetTile(long, long, int) overload, so it may not account for the scaling that is present in the other method.

NodeTileHelper.GetTile(526868344, -18000386, i);

In addition the following code in the scaling method recursively calls itself, because of the variable declarations. In order to account for the different method, you will need to convert lat and lon to long types.

double lat, lon;
// ...
return GetTile(lat, lon, zoom);

Given the original stored procedure definition, I think it would make more sense to consolidate this into one method instead of using overloads. Alternately, I think using different names for the methods would make it clearer than simply using the difference between parameter types (eg,. long vs. double ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM