Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix slowness on proj_create_crs_to_crs() on WGS 84 <--> UTM conversions #4319

Closed
plumewind opened this issue Nov 11, 2024 · 11 comments · Fixed by #4320
Closed

Fix slowness on proj_create_crs_to_crs() on WGS 84 <--> UTM conversions #4319

plumewind opened this issue Nov 11, 2024 · 11 comments · Fixed by #4320
Assignees

Comments

@plumewind
Copy link

problem

When using proj-9.5.0, find very slow on proj_create_crs_to_crs().
My code like this:

  int zone = static_cast<int>((lon_rad * 180 / M_PI + 180) / 6) + 1;
  std::string latlon_src =
      "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs";
  std::string utm_dst =
      absl::StrCat("+proj=utm +zone=", zone, " +ellps=GRS80 +units=m +no_defs");

  PJ_CONTEXT *C = proj_context_create();
  PJ *pj_latlon =
      proj_create_crs_to_crs(C, latlon_src.c_str(), utm_dst.c_str(), NULL);
  if (0 == pj_latlon) {
    fprintf(stderr, "Failed to create transformation object.\n");
    return false;
  }

  PJ *norm = proj_normalize_for_visualization(C, pj_latlon);
  if (0 == norm) {
    fprintf(stderr, "Failed to normalize transformation object.\n");
    return false;
  }
  proj_destroy(pj_latlon);
  pj_latlon = norm;

  PJ_COORD a = proj_coord(lon_rad * RAD_TO_DEG, lat_rad * RAD_TO_DEG, 0, 0);
  PJ_COORD b = proj_trans(pj_latlon, PJ_FWD, a);
  utm_xy->x = b.xy.x;
  utm_xy->y = b.xy.y;

  proj_destroy(pj_latlon);
  proj_context_destroy(C); 

Problem description

When I was processing the conversion, I found that the process was very slow. Then, I counted the time taken for each process and found the following:
image

Expected Output

Normally, this process on proj_create_crs_to_crs() should be very fast, almost 0 milliseconds.

Environment Information

  • PROJ version (proj-9.5.0)
  • Operation System Information (ubuntu 20.04)

Installation method

mkdir -p build           
cd ./build              
cmake .. -DBUILD_SHARED_LIBS=ON -DBUILD_TESTING=OFF -DCMAKE_INSTALL_PREFIX=/opt 
 -DCMAKE_BUILD_TYPE=Release
make
sudo make install
@plumewind plumewind added the bug label Nov 11, 2024
@jjimenezshaw
Copy link
Contributor

Have you tried adding +type=crs to both CRSs?

@rouault
Copy link
Member

rouault commented Nov 11, 2024

Have you tried adding +type=crs to both CRSs?

proj_create_crs_to_crs() automatically adds its

found that the process was very slow.

Well 16 ms is not so bad for something that involves looking in a database. In that particular case, we could perhaps avoid the database lookups given both CRS involve unknown datums, but haven't looked more closely.

The general advice is that you should keep the objet returned by proj_create_crs_to_crs() to transform many points, rather than recreating it each time

@rouault rouault added enhancement and removed bug labels Nov 11, 2024
@rouault rouault self-assigned this Nov 11, 2024
rouault added a commit to rouault/PROJ that referenced this issue Nov 11, 2024
…ically PROJ strings) using unknown datums

Fixes OSGeo#4319

With that improvement, the runtime of the following snippet goes from
25.4 second to 0.9 second:
```c
    for(int i = 0; i < 2000; ++i)
    {
        PJ_CONTEXT *C = proj_context_create();
        PJ *P = proj_create_crs_to_crs(C,
           "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs",
           "+proj=utm +zone=31 +ellps=GRS80 +units=m +no_defs", NULL);
        proj_destroy(P);
        proj_context_destroy(C);
    }
```
rouault added a commit to rouault/PROJ that referenced this issue Nov 11, 2024
…ically PROJ strings) using unknown datums

Fixes OSGeo#4319

With that improvement, the runtime of the following snippet goes from
25.4 second to 0.9 second:
```c
    for(int i = 0; i < 2000; ++i)
    {
        PJ_CONTEXT *C = proj_context_create();
        PJ *P = proj_create_crs_to_crs(C,
           "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs",
           "+proj=utm +zone=31 +ellps=GRS80 +units=m +no_defs", NULL);
        proj_destroy(P);
        proj_context_destroy(C);
    }
```
@plumewind
Copy link
Author

First of all, thank you very much for your reply.

I understand everything you said, but my current requirement is a one-time conversion tool to convert the coordinates of several points, and the positions of the points are not regular, in other words, their zone numbers are random.

I used version 7.1.0 before and it was great to use. The code is as follows:

  projPJ pj_latlon;
  projPJ pj_utm;
  int zone = static_cast<int>((lon_rad * RAD_TO_DEG + 180) / 6) + 1;
  std::string latlon_src =
      "+proj=longlat +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 +no_defs";
  std::string utm_dst =
      absl::StrCat("+proj=utm +zone=", zone, " +ellps=GRS80 +units=m +no_defs");
  if (!(pj_latlon = pj_init_plus(latlon_src.c_str()))) {
    return false;
  }
  if (!(pj_utm = pj_init_plus(utm_dst.c_str()))) {
    return false;
  }
  double longitude = lon_rad;
  double latitude = lat_rad;
  pj_transform(pj_latlon, pj_utm, 1, 1, &longitude, &latitude, nullptr);
  utm_xy->x = longitude;
  utm_xy->y = latitude;
  pj_free(pj_latlon);
  pj_free(pj_utm);

But now, after upgrading to 9.5.0, I find that the previous code cannot run, and I eventually realize that this time-consuming process is very troublesome. Can you improve it? Thank you.

@rouault
Copy link
Member

rouault commented Nov 12, 2024

their zone numbers are random.

they can not be that random. They must be between 1 and 60, so you could pre-compute 60 transform objects and re-use them

Can you improve it?

Cf #4320

@plumewind
Copy link
Author

They must be between 1 and 60,

Haha, I definitely know, it must be within 1-60!
Thank you.

@plumewind
Copy link
Author

Cf #4320

How can I pull the latest code for verification?

@plumewind
Copy link
Author

pre-compute 60 transform objects and re-use them

Good idea, I can improve it later!

@rouault
Copy link
Member

rouault commented Nov 12, 2024

How can I pull the latest code for verification?

https://github.com/rouault/PROJ/archive/refs/heads/fix_4319.zip

@plumewind
Copy link
Author

How can I pull the latest code for verification?

https://github.com/rouault/PROJ/archive/refs/heads/fix_4319.zip

That is great!
image

@kbevers
Copy link
Member

kbevers commented Nov 12, 2024

@plumewind if you don't mind, what sort of use case do you have where a 16 ms one-time wait is critical?

@plumewind
Copy link
Author

@plumewind if you don't mind, what sort of use case do you have where a 16 ms one-time wait is critical?

Well, we use it in pose estimation scenarios for high-speed moving objects. However, just now, I have changed this tool to singleton mode.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants