321 | | |
322 | | |
323 | | |
324 | | [#q22 22. How does rendering work?] \\ |
325 | | |
326 | | [#q23 23. What are main ideas for further LAG development?] \\ |
327 | | [#q24 24. What are some major issues with LAG that need fixing?] \\ |
328 | | [#q25 25. What are some additional features that can be added to LAG?] \\ |
329 | | [#q26 26. What tools are there to help me with LAG development?] \\ |
330 | | |
| 324 | When 1.3 or higher format is recognised //LoadWorker::load_points_wf()// method is used which creates //LidarPoint// objects to be inserted into the quadtree as well as //PointData// objects which hold the remaining attributes. A temporary file is created for each flightline and //PointData// objects are serially written to it. The //point_data_paths// is used to map a flightline number to a name of a temporary file where //PointData// objects are stored and //point_number// vector holds the number of points currently loaded per flightline. This number is also assigned to //LidarPoint::data_index// so the exact location of its data in the temporary file can be retrieved by using //LidarPoint::data_index// x //sizeof(PointData)//. Not that the actual waveform data is not touched during the process.\\ |
| 325 | When LAS 1.3 points are saved the location of temporary file is retrieved inside {{{SaveWorker::save_points_wf()}}} method from {{{LoadWorker::point_data_paths.find(flightline_number)}}}. Then for each saved point it corresponding {{{PointData}}} is retrieved from the temporary file with like this: |
| 326 | {{{ |
| 327 | #!div style="font-size: 100%" |
| 328 | {{{#!c++ |
| 329 | char* buffer = new char[sizeof(PointData)]; |
| 330 | PointData* temp; |
| 331 | int s = sizeof(PointData); |
| 332 | |
| 333 | fseek(datafile, points[k].getDataindex() * s, SEEK_SET); |
| 334 | fread(buffer, s, 1, datafile); |
| 335 | temp = (PointData*) buffer; |
| 336 | }}} |
| 337 | }}} |
| 338 | Because laslib library doesn't support storing waveform data in the same file as point records it automatically sets {{{start_of_waveform_data_packet_record}}} field in the header to 0. We need to manually change it to the correct value: |
| 339 | {{{ |
| 340 | #!div style="font-size: 100%" |
| 341 | {{{#!c++ |
| 342 | fseek(fileout, 227, SEEK_SET); |
| 343 | fwrite(&reader->header.start_of_waveform_data_packet_record, sizeof(I64), 1, fileout); |
| 344 | }}} |
| 345 | }}} |
| 346 | Finally we copy over the waveform data manually and attach it to the end of the output file. Note that this requires for LAS 1.3 files to be saved to a separate file after modification. Unfortunately there is no way around this with how laslib library currently works. |
| 347 | |
| 348 | === 22. How does rendering work?] [=#q22] === |
| 349 | |
| 350 | It's difficult to tell. It's quite a mess and it definitely needs some refactoring for maintainability. It does work however so I haven't changed it, focusing on other things. \\ \\ |
| 351 | |
| 352 | Once the files have been loaded, a pointer to the quadtree is passed to {{{LagDisplay}}}, {{{TwoDeeOverview}}} and {{{Profile}}}. First {{{LagDisplay::prepare_image()}}} method is called which sets up OpenGl and gets all the buckets from the quadtree with {{{advSubset()}}} method. Based on the ranges of z and intensity values it then sets up arrays for coloring and brightness of the points in {{{LagDisplay::coloursandshades()}}}. Then {{{resetview()}}} method is called which sets up orthographic projection and conversion of world coordinates to screen coordinates. \\ \\ |
| 353 | After that a {{{drawviewable()}}} method is called in {{{TwoDeeOverview}}} and/or {{{Profile}}} which checks what part of the data is currently being viewed on the screen and gets the relevant buckets from the quadtree. It also uses a good number of boolean variables which are changed all over the place to make things harder to understand.If you were wondering how NOT to do threading in C++, here's a great example. Eventually we create a new thread and call {{{TwoDeeOverview::mainimage()}}} method passing it the buckets we've got. \\ \\ |
| 354 | |
| 355 | In {{{mainimage()}}} we call {{{drawpointsfrombuckets()}}} which prepares the points for being drawn. For each bucket from the quadtree it determines the resolution level needed (sub-bucket) based on the current zoom and viewing area. Then for each point in that bucket it creates vertices with attributes of the point to be drawn (location, color, brightness) and passes them to {{{DrawGLToCard()}}} method in the main thread which draws the contents of the vertices to the framebuffer. Finally {{{FlushGLToScreen()}}} method draws the contens of framebuffer to the screen. \\ \\ |
| 356 | |
| 357 | Simple as that. |
| 358 | |
| 359 | === 23. What are main ideas for further LAG development? [=#q23] === |
| 360 | |
| 361 | There are few categories of things that need to be done: |
| 362 | * things that have been started but haven't been quite finished |
| 363 | * issues that need fixing |
| 364 | * additional features |
| 365 | |
| 366 | To add to that there's still plenty of refactoring to be done (possibly a good thing to start with to understand the code better). Particularly the rendering, which works, but is kind of scattered between different classes and methods and its threading which is just bad. Ideally there should be a separate Renderer/RenderingWorker class with all the code in one place. |
| 367 | |
| 368 | === 24. What is the unfinished development stuff? [=#q24] === |
| 369 | |
| 370 | That's mainly sorting out the threading. While LoadWorker and SaveWorker have been fully implemented, the ProfileWorker and ClassifyWorker need some improvement (so the job is actually done inside these classes). To add to that a progress indication for classifying points and loading a profile could be added. \\ \\ |
| 371 | |
| 372 | Add more things here. |
| 373 | |
| 374 | === 25. What are some major issues with LAG that need fixing? [=#q25] === |
| 375 | |
| 376 | Luckily there's not so many any more, however the major one is the memory consumption. This is quite a difficult problem, but it has to be looked at before lag can be released to the public. \\ |
| 377 | Another one is handling of the LAS 1.3 files. \\ |
| 378 | Also there is an issue with rendering/loading thread where forcing ON_EXPOSE event while loading a file at the same time may sometimes cause a segfault. For example moving some window on top of the TwoDeeOverview window while file is being loaded may cause this. This is most likely cause by both loading and rendering thread trying to access the quadtree at the same time and I believe sorting out the rendering thread should solve this problem. |
| 379 | |
| 380 | === 26. What is lag memory issue? [=#q26] === |
| 381 | |
| 382 | It's an unknown source of high memory consumption of LAG. It looks like either a memory leak, memory fragmentation or both. The reason to suspect memory fragmentation is that the memory usage keeps growing to some point then stays constant. It's easy to see when loading the same file multiple times. Also when using a heap profiler it will show correct and constant memory usage and will not grow as high, possibly because of custom memory pool from the profiler. |
| 383 | |
| 384 | Probably the best way to fix it would be to create a [http://en.wikipedia.org/wiki/Allocator_(C%2B%2B)#Custom_allocators custom memory allocator] which is an interesting project on its own. |
| 385 | |
| 386 | === 27. What are some additional features that can be added to LAG? [=#q27] === |
| 387 | |
| 388 | Here are some ideas: |
| 389 | * A 3D overview. Not so useful for processing, but pretty cool for visualisation and possibly attractive for other users outside ARSF (once LAG is released to the public). |
| 390 | * Additional Loading/Saving features. For example an option to use shape files to filter out points, ability to import/export different file formats, support for more projections etc. Also improved support for waveform data. |
| 391 | * Plugins or scripting support. Probably scripting would be easier to implement, for example using boost::python. The idea is to provide an interface for lag/quadtree to a scripting language like python so even users that don't know C++ could add their modifications. For example classify_las could then be made a script or tool inside lag. |
| 392 | * Further GUI improvements. Eg. progress bars for loading a profile and classifying points, tool tips and other user-friendly stuff. |
| 393 | * Waveform visualisation. |
| 394 | * Multi-platform support. |
| 395 | |
| 396 | === 28. What tools are there to help me with LAG development? [=#q28] === |
| 397 | |
| 398 | I'd recommend the following: \\ |
| 399 | [http://sources.redhat.com/gdb/ Gdb] - best debugging tool on Linux.\\ |
| 400 | [http://valgrind.org/ Valgrind] - an excellent set of tools for profiling, optimisation, memory leak detection etc. \\ |
| 401 | [http://code.google.com/p/gperftools/ gperftools] - a set of performance analysis tools from Google. \\ |
| 402 | |
| 403 | === 29. How do I use profiling tools to optimise code? [=q29] === |
| 404 | |
| 405 | Profiling is better then your intuition when it comes to optimising code and you should do it often. It lets you easily identify bottlenecks and see how your changes actually affect the performance. It also lets you pinpoint functions that cause high memory consumption and find possible memory leaks. \\ \\ |
| 406 | To be able to use all features of profiling tools you'll have to compile your code with {{{-g}}} and {{{-pg}}} flags. In case of lag and quadtree in means adding them to Makefile.am AM_CXXFLAGS. They should be removed before rolling out a new release though as they negatively affect both performance and size of the executables. \\ \\ |
| 407 | To get an idea about call times and frequencies of the functions you can use valgrind tool called callgrind. You run it like this: |
| 408 | {{{#!sh |
| 409 | valgrind --tool=callgrind lag |
| 410 | }}} |
| 411 | The lag will start as usual however it will run extremely slow. Run some operations (possibly such that you can repeat with no variations, like loading a single file) and close the program. The callgrind will have generated a call-graph file called callgrind.out.xxxxx which you can open in {{{kcachegrind}}} for visualisation. |
| 412 | |