Some leaflet and javascript gotchas, part 1
I have been playing ouround with various javascript libraries because I want to load output from LSDTopoTools directly into a browser rather than having to click a bunch of buttons on a GIS.
This unfortunately involves learning some javascript, which is not so easy to debug.
Here are a few gotchas.
- If you are working on a local server, you can mix
http
andhttps
source files. But if you want to see things on the bl.ocks website, everything needs to be at the same security level. You browser will not tell you about this problem. I would default tohttps
. For leaflet you need:
https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.css
and
https://cdnjs.cloudflare.com/ajax/libs/leaflet/0.7.3/leaflet.js
whereas D3 is:
https://d3js.org/d3.v3.min.js
- Another thing is that you might want to add some leaflet plugins. These are great but you MUST add the link to the plugin AFTER you have provided the leaflet script, like this:
Getting a local http server working
I’ve been messing about with various visualisation using D3 and leaflet. These tools are great but they interact with a browser and you will want to check your code before sending it to a Gist so that it can be rendered on Bl.ocks.
To do this I use a nodejs application called http-server. Before you install it you need to install something called Nodejs.
The links have all the documentation for doing so.
Once you have that installed, you simply navigate to your folder with your website in either a terminal or powershell, and type http-server
. When you are finished, type ctrl-C
.
Debugging TopoTools
DAV - Some notes mainly for my own use - I guess other folk have their favourite debugging methods
When I first started ‘debugging’ I would simply insert std::cout
statements into the code before the suspect line of code that was causing the crash or bug, to get it to print out variable values and so on. Then people started talking about this magical tool called gdb (The GNU debugger), which would run your program for you and then print out the most recent function calls and variables just before your code crashed.
GDB requires you to compile your code in a certain way - you must set any optimisation flags to either -O0
or Og
, and you need to set the compiler to generate debugging information when it builds the executable. This is done with the -g
flag or even -ggdb
flag to get gdb specific deugging information. So your makefile might look something like this:
To debug your new executable run gdb ./MyExecutable
, note that you don’t specifiy any command line arguments at this stage, as is normally done with the LSDTopoTools executable files. This is done in the next stage, so after gdb loads, type run [PATH_TO_INPUT_DATA] [PARAMETER_FILE]
, (or whatever command line arguments and options your executable expects to receive. The program will run as normal, and output the usual stuff to the terminal.
If your program gets to a point where it crashes, however, it will print out the error that terminated the program (often something like Program received signal SIGSEGV, Segmentation fault
), but it will print out the very last function call and tell you the line number of the source code where the fault occurred.
Sometimes, the output is confusing because it doesn’t relate directly to one of your source code files. For example if you have a segmentation fault in the LSDTopoTools code, it may well say that the error took place in one of the TNT/Template Numerical Toolkit library headers. (like Array2D.h
or similar). Since it’s unlikely that the real cause of the bug or crash occurred in one of these library files (though not impossible), you can trace further up the call stack (i.e. list of functions that were called that lead to this crash), by typing backtrace
or just bt
for short.
Hopefully, you should eventually see one of your source code files in the stack trace, and the line number in the corresponding source code file. It will also print the value of any local variables at the line number which are in scope. That is as far as it goes - it won’t tell you exactly where on that line the error happened, but at least it has narrowed it down quickly!
More detailed debugging info
If you want even more debugging information, you can type backtrace full
or bt full
and the debugger and it will print out all the variables in the current scope, as well as all the global variables. Note this is a massive terminal-filling tome of output!
As LSDTopoTools uses a lot of the Standard Template Library functions, (std::vector, std::string, etc…), these can often result in puzzling debug messages. You can get a slightly more comprehensible output by adding the -D_GLIBCXX_DEBUG
flag to your CPPFLAGS in the makefile. If you get the gdb message missing separate debuginfos
or similar, you might need to install a few separate linux packages before you can take advantage of this feature, see this StackOverflow question for more information.
Beyond GDB
ddd
ddd is basically a GUI interface to gdb. It makes it easier to set breakpoints within the code at certain line numbers, or to track whether certain variables change. You can do all of this in plain-old terminal based gdb, but I find ddd a bit easier to use for this kind of stuff.
Valgrind
Valgrind is a really useful tool for finding bugs that gdb/ddd would be unable to do. For example gdb is unable to tell you if you have code that can result in out of bounds array indexing, or might crash due to uninitialised variables, because it can only trace bugs that occur at run time, which may be dependent on the data/DEM or set of parameters you are currently using. Valgrind is better at finding where things might go wrong, even if your program isn’t currently crashing. It’s also used to find memory leaks - i.e. where memory is allocated for a data stucture but never deallocated.
The main things I use Valgrind for:
- Out of bounds array index checking
- Finding conditional statements that are based on variables that might be uninitailised.
- Finding memory leaks.
Valgrind is used with the command valgrind [VALGRIND OPTIONS] ./MyProg.out [ARGUMENTS] [OPTIONS]
The two most useful options I tend to use with valgrind are --leak-check=yes
(to find memory leaks), and --track-origins=yes
, which gives a bit more detail in where your program crashed/might crash. Both of these options, and valgrind in general, add a considerable amount of memory usage to your program, and run time is general much slower than a standard debugging run with gdb/ddd. However it’s a very useful tool.
Forward declaration of classes
Based on email from SMM ages ago and some stuff I read off stack overflow…
Some of the classes/objects in LSDTopoTools rely on access to other objects in different classes. For example, the some of the LSDIndexRaster
member functions take LSDRaster
objects as arguments passed to the functions. One way to make these external classes available is to #include
the relevant header file that conains the class. This is OK, but can lead to problems with circular dependencies if two header files reference each other’s classes.
LSDIndexRaster.hpp
LSDRaster.hpp
The solutuion to this cyclical problem is to use a forward-declaration of the class LSDRaster in the LSDIndexRaster.hpp file. Forward-declaration just tells the compiler that this class exists – it doesn’t tell the compiler about any of the class details, but it’s sufficient for the purposes here.
LSDIndexRaster
Templating the LSDRaster object - DAV
Don’t worry, I haven’t actually changed LSDRaster in the trunk
LSDRaster uses float
s to store it’s data arrays. Floats are fine for more purposes, (they take up less memory than arrays of double
s for example, and you don’t always need the extra precision of double anyway. But I wanted an LSDRaster
object that used arrays of doubles to maintain compatibility with some other code, so I experimented with the best way of doing this.
Extra data members, overloaded functions
The easiest way is just to create a data member in the LSDRaster class that stores an array of doubles, and then write seperate functions to deal with creating this object, and manipulating it. You can overload functions if they take TNT::Array2D<float>
arguments with the corresponding <double>
typename.
Unfortunately, this leads to a lot of code duplication, and extra data members in the LSDRaster class with funny names, RasterData_dbl
, for example. It’s fine, but a bit clunky.
Templates
So I figured that it might be possible to create a templated class for LSDRaster. Templates allow a class to be spawned for different data types at run-time. The TNT::Array2D<>
class is an example of a templated class, as you specifiy the data type when you create your object, e.g TNT::Array2D< int >
, or whatever you like.
I had a shot a converting LSDRaster to a template class like so:
So, in theory, we could now create LSDRaster objects with arbitrary type for the array data (Well, not completely arbitrary - it has to be supported by TNT::Array2D.). If we wanted an array of doubles, we could do:
This is good so far, but it raises a few issues. Firstly, the declaration for an LSDRaster
object is now LSDRaster<typename>
and any instance of LSDRaster
in the code will not compile as the typename is incomplete, and your compiler will complain. Secondly, you cannot write the implementation of a template class in a separate .cpp
file, like you can with a normal class. See this SO answer for details. There are ways of getting round this, for example by including the .cpp
file in the header file, and so on.
But anyway, even if we got around the second issue above, there is still the problem that this new LSDRaster<> template has broken everyone’s code that contains any use of LSDRaster obj
. After some more reading, I though it might be possible to use a typedef
to subvert this, and stop everyone’s code from breaking.
typedef
just says that we want to use a synonym LSDRaster
to mean LSDRaster<>
(Incidentally, LSDRaster<>
without any type given inside the angle brackets, will default to float, as it was specified in the template definition as: template<typename T = float>
)
Unfortunately, you can’t do this within a class - a typedef
can’t have the same name as it’s enclosing class, and we need this inside the class because some of our functions take LSDRaster
objects (or references) as arguments. You also have to put the typedef
in all the other classes that use LSDRaster
objects.
The only way of getting around this would be to give the LSDRaster class a different name, something like:
And this would be ok, but you’d still have to change a lot of people’s code…
(TBC…)