 Okay, welcome to the second boost geometry talk today. I'm Adam, I work at MySQL, and I'd like to talk about spatial reference systems and how to transform between them in C++ with boost geometry. So when we are dealing with coordinates, we have to know the context for them, how to interpret them, they may be on the surface of spheroid or on the sphere, we have to know the parameters of the spheroid or maybe these coordinates are on a map, so they are Cartesian coordinates. In this case we have to know how this map was created to interpret them properly. The most simple thing that could go wrong is missing of units. For instance, we could have a coordinate system using meters or feet. Typically, this is what the space reference system defines. It defines the context of coordinates we are using. Typically, the space reference system is referred to with a number. There are some multinational organizations defining such numbers. The most known one is the EPSG, which is now a part of International Association of Foreign Gas Producers. There are others like ESRI and there are also numbers of space reference systems for objects in space, like moon or other planets. This is the last one mentioned on the slide. Here we can find various coordinate systems defined. The first two ones are defined by resources for EPSG reference systems and the third one contains also ESRI and the astronomical ones. When you go to one of these sites, you will see basically two definitions. This is the first one, so this is the WKT format, a well-known text as defined by the open geoconsortium. This is basically the standard one. This particular one defines the standard WGS-84 coordinate system, so longitude, latitude, and spheroid in degrees. Basically, the data you are seeing, for instance, in some GPS to return coordinates in this system. This is the same coordinate system defined in approach four string. Approach four is a well-known library written in C with wrappers to many languages, and this is how projections are defined in this library. During this talk, I will be talking about approach four. Actually, I will be talking about boost geometry, but with relation to approach four because this is the state-of-the-art library. The most recent version is 5.2, and here are the addresses. Boost geometry implementation is based on approach four. It was started some time ago by Baron Gajaros when approach four was in version four, or three, or something like that, and I finished it. Most of the things you will see are already released in Boost 169, and some of them will be in 170. This presentation will be example-driven, so this is my data. I took the data from Eurostat. This is basically boundaries of countries of the world represented as polylines. Here is the address at the top, and you have to navigate to find the file. As you can see, at the end of the file, I'm using a shapefile, and these are coordinates in WJS-84, which is EPSG 4326. This is how it looks like. What I would like to do basically is I would like to create three maps. These are geographic coordinates. I will be creating three maps, one of Poland, one of Belgium, and one of New Jersey. I will say why New Jersey later. These are all geographic coordinates of boundaries of Poland and neighboring countries. I know if you know what the shape of Poland is, but this is distorted. What I would like to do is to create a map representing the reality more closely, more accurately. For this purpose, this SRID is used, so EPSG 2180. It's used for maps of scales to 1,000 to 10,000, I think, because for closer scales you have to use another one. The SRID is called, there are two other names behind the EPSG code. The first one is the European one, and the last one is Polish name for this projection. So how it's defined? This is the definition in WKT. As you can see, it's on a different spheroid than WJS-84. It's a force line in degrees, and these coordinates are projected using transverse mercator projection, which is something like this, if we project the whole world. This is how it's done in C++, because I'm using vector, in row approach 4. So we are creating two projections. PJ init plus takes approach 4 string, so this different kind of defining a projection than WKT. I shown at the beginning. Then I have some array of coordinates, which here is a vector, and I'm calling PJ transform function passing the coordinates. And I have to free the projections, because essentially these are pointers. Before that, in boost geometry, we can express the abstractions directly in the code. So here I'm expressing geographic points, line strings, and creating multi-line strings, and doing the same for Cartesian, because my input will be geographic and the output will be Cartesian. And here is how it looks like in boost geometry. This is one possibility, I will later show other ones, but this is the basic one, the closest to approach 4. So we are just passing the same approach 4 strings. The only difference is that in C++, the creation and destruction is handled automatically, and I'm passing input multi-line string, which is geographic, and as output multi-line string, which is Cartesian. And I get the transformation you've seen before. So another example, the same story, Belgium row geographic coordinates, and this is how it should look like. Again, standard space reference system for Belgium, number EPSG 31370. So this is the definition from yet another spheroid using degrees and using a different kind of projection. So before there was Transverse Merkite and here we have Lambert Connick. So this is the way you've already seen, how to create the transformation in boost geometry. So the first one, the first projection is from which we are transforming, and the second one is projection to which we are transforming. So we are transforming from WDS-84 to this map projection with high number of parameters. So this is the first possibility. So obviously the strings has to be parsed, parameters extracted, which takes time. But there is a better way, which looks like this. It's very similar, the names of parameters are the same. However the numbers are expressed directly in the code, which means that they doesn't have to be parsed. Obviously this should be faster. Here you can see the two WDS-84 parameters, which are parameters used in conversion between ellipsoids. And I'm passing C++11 initializer list as range, but you can pass any range you like. But there is yet another way, because here parameters are added to the list in runtime. But you can create a list in compile time. It should be even faster. When you pass a type, well two types representing projections into transformation as template parameters, then the projection exactly knows what you will pass in the constructor. And it expects exactly what you defined in the type. So this should be even faster. And I also benchmark that it is really. But there is another way. So if you include this optional header, which contains a lot of EPSG codes, there is a 7000 or something like that, which increases the compilation time greatly. But if you enable it, if you include it, then you can simply pass the numbers. So the upper one is the runtime version, and the lower one is compile time version. Which below the surface is the interfaces I've shown on previous slides. And here are the benchmarks for the Belgium set. It contains 7000 points, roughly. So in the table above, there are creation times. And in the table below, there are transformation times. So 5,000 creations of transformation object and adequate approach for projections. And below the transformation of the coordinates. And as you can see, right. And in the first column, you have project prot4. In the second column, there is both geometry using prot4 strings. The third one is both geometry using the runtime parameters directly expressed in the code. And the last one is static parameters. So as I said, the creation is faster with both geometry in all cases. We are parsing the strings differently, too. So this is why we're faster than even in case of prot4 strings. And we are slightly faster in case of transformation itself. Because internally, oh, we are doing things differently, too. And this is the last example, New Jersey. I'm showing New Jersey because as you will see, it uses North American Dayton 27, which requires to use grid shifting. So instead of transformation between ellipsoid using a set of numbers or an array, we are transforming between ellipsoid using grids. So look out table, basically. And this is the first SLID I found in the US because it basically is used by the US and Canada areas, which isn't yet deprecated and was near the sea. So we could see the boundaries. So this is the definition in WKT. The interesting thing here is that previous projections used meters, but here we have feet. It's a fifth line from the bottom. So this way you've seen already from WJS-84 to this another kind of projection. If you do this in boost geometry, the grids won't be used. So in boost geometry, unlike in Proch4, you have to explicitly define where the grid storage will be stored and you have to initialize them explicitly and pass. It's because Proch4 does it under the hoods, looks for grids which are basically huge text files, maybe not text, probably it depends. Huge files somewhere on a disk. Proch4 looks in some standard directories like the directory of a program or a user directory. So this is not acceptable, I think. So here you have to do it manually. And here's the, let's say, one thread example. So I'm creating grid storage. I'm passing stream policy and grids. So the first parameter tells how to access the file. So it defines what kind of stream and how to open it because you can have a grid in a string already loaded, whatever you like. So this default one searches for a file in the program directory and uses ifStream. And the second parameter grids is the way to tell the library to use single threading. And then we are creating the transformation and initializing grids which then they are passed to forward methods. So the only difference if you want multi-threading, the only difference is that instead of SRS grids, you have to pass shared grids. And currently shared grids use boost thread, so you have to link this library if you want to use them. I think in the future it will be possible to use STD threads. However, as far as I remember, internally I used unique lock and shared lock and I'm not sure when they were added to the standard. It's possible that in C++17 this is why I used boost thread. I would have to check it. So the same story, storage, which may be defined anywhere and basically should be shared between all transformations because it's more or less a global thing as you don't want to load the same file multiple times. But this way you have control on when it will be created, when it will be destroyed, you can destroy it or keep it unlike in Proch4 I think. Then transformation in initialization of grids and two threads performing transformation. Now what's the difference between grid shifting and without grid shifting? So we are going to Atlantic City and the red one is without and blue one is with shifting. So the difference is 100... Can you see these little numbers? It's more or less 100 feet, so it's around 30 meters error. If you don't use it. But if you are fine with it, then it will be faster. So again, boost geometry is faster and this time the difference is bigger because basically the grid shifting code was rewritten and we are using modern... in case of shared grids, we are using modern locking mechanisms like Uniklock and Sharedlock unlike Proch4 which I think use simple motexes, as far as I remember. And in case of boost geometry, you can explicitly don't use grids, which makes it very fast compared to using grids, but you don't get the accuracy. So boost geometry is flexible, fast, it's easy to achieve thread safety because with Proch4, with previous version of Proch4, it was not possible to be thread safe because they were using global error reporting mechanism like this error no system tool. Now it is possible, but you have to create production context one per each thread and use a different function. So additional code and with boost geometry, because after you create the transformation, it's constant, you can just use it with multiple threads. You don't have to do anything else. Unfortunately, there are less features in boost geometry. So if you need some less common stuff like geo grids or 3D transformations or pipeline operator, then you'd have to use Proch4. And in boost geometry, there's also no init parameter and no access parameter. They're not supported because in boost geometry, the order of coordinates is defined at compile time. But I think this might be changed because it might be, maybe would be needed in some cases. But there is no init because in Proch4, init also loads EPSG, for instance, various things from files. And this is something you'd like to avoid. Right, and if you're wondering how these pictures were created with this extension. Thank you. Shall we sort of get to the left and the right like this? Sure. Do you have any plans to add additional dimensions? I work with robotics, and the geometry is great. One of the, like, robots have many axes and projections are very important. Right, but for robots? For robots, right. You're talking about, for instance, robot arm, right? So this would probably be different kinds of transformations, right? Which should probably be faster than what I've shown. So maybe boost QVM would be for you because they have matrices and quaterions. So maybe something you'd like to use instead. Well, there is, in boost, there is a function called transform where you can pass a matrix defining the transformation and this way transform anything, any geometry you like. So this is also what you could use. So either this or QVM, but probably not SRS transformations. It's in the future plans. Right, so yeah, we plan to add 3D and actually 4D because there are also additional data which can be passed with points. But it's not there yet. But yeah, we are planning it. Which ellipsoidal transformation methods? Right. Yes, it's under the hood. It's basically the same code as Proch4 because it started as, well, not a port, but it was heavily tinkered with. But it was basically Proch4. And it was started mainly because, this way, mainly because Proch4 only use doubles and boost geometry allows to define any coordinate type. But yeah, we are using the same method and between ellipsoids 2WGS it's used or NAD grid, because it depends on datum. So in this rare case of North American datum grids are used instead of 2WGS. And in some cases, actually I was not entirely honest with you because there is a rare case of 3D representation of coordinates which is centered Earth fixed, which is also supported. But yeah, I'm not talking about that right now because it's a different story. Yeah, so we are using the same method as Proch4. I don't understand the question entirely. Oh right, something like CS2CS. You're talking about calling a tool from Linux command line. Right, no, there is... There is Proch4 based one. It's called CS2CS with two as a number. We have the Proch4 strings and you have your own dynamic and side of the defined things. Which boosters do you need to get those? 169, but without... with all of the things I showed here, compiling without problems 170, which is not there yet. But most of the things will work. Okay, thank you.