As a follow-up to my prior post, this is how to use the Cube Voyager API to read a path file. I highly recommend you read the other article first, as it talks more about what is going on here.
The interface for the path reader is larger because of the return structure. The code below includes the interfaces to the DLL calls and the structure for the path data returned by some of them. Note that I didn't do PathReaderReadDirect. It doesn't seem to work (or I'm not trying hard enough).
Once the interface is in place, the code is reasonably simple. However, I'm seeing a few interesting things in the costs and volumes in both C++ and in Java, so I wouldn't use those values. I guess if you need to determine the costs, you should save the costs with the loaded highway network to a DBF file and read that into an array that can be used to store and get the values.
The Final Word... For Now
Java is a great programming language. Using these DLLs can help you do some interesting stuff. However, it seems that there are very few people using the API, which is concerning. I personally would like to see an interface for reading .NET files and writing matrices. But I can't expect Citilabs to put time in on that when it seems there are so few people using it.
I've begun to really enjoy Java. It's hot, black exterior exposes a sweet bitterness that matches few other things in this world. Oh, wait, this is supposed to be about the other Java - the programming language!
The "Holy Grail" of API programming with Cube Voyager to me has been using the API in Java. I can program in C++ quite well, but I have a staff that can't. We're likely going to be going to a Java based modeling structure in the next few years, so it makes sense to write everything in Java and keep the model down to two languages - Cube Voyager and Java.
Setting up the Java Environment
There are three things to do to setup the Java environment to make this work. The first is to place the Cube DLL in the right location. The second is to get JNA and locate the libraries to where you need them. The final is to setup the Java execution environment.
First, copy the VoyagerFileAccess.dll file (and probably it's associated lib file) to C:\Windows. It should work. I'm using a Windows 7-64 bit machine, so if it doesn't work, try C:\Windows\System32 and C:\Windows\System.
Second, get JNA. This allows the Java compiler to connect to the DLL. The latest version can be downloaded from Github (go down to "Downloads" under the Readme.md... just scroll down 'till you see it, and get both platform.jar and jna.jar).
If you're on a 64-bit computer, the second thing to do is to set your jdk environment to use a 32-bit compiler. I use Eclipse as my IDE, so this is done through the project properties. One location is the Java Build Path - on the Libraries tab, make sure the JRE System Library is set to a 32-bit compiler. In the Java Build Path screenshot below, you can see that all the locations are in C:\Program Files (x86) - this is an easy (although not foolproof) way to show that this is a 32-bit compiler.
While you're setting up stuff in this window, make sure the jna.jar and platform.jar are linked here as well (click "Add External JARs..." and locate those two files).
Another place to check in Eclipse is the Java Compiler settings, which should have "Use Compliance from execution environment..." checked.
The thing that makes this work is this part of the programming. You can see in this that I create an interface t0 the Voyager DLL file by loading the DLL, and then setup some pointer objects to hold the memory pointer variable (the "state" variable in all of these) and set up the functions to read from the matrix.
The next part that makes this work is the actual programming. In the code below, the first thing I do is define vdll as an instance of the voyagerDLL interface. Then, I open a matrix file (yes, it is hard-coded, but this is an example!), get the number of matrices, zones, the names, and I start reading the matrix (in the for loops). I only print every 100th value, as printing each one makes this slow a bit. The actual reading is quite fast. Finally, I close the matrix and the program terminates.
The big issue I noticed is that if the matrix is not found, the Pointer variable returned by MatReaderOpen will be null, but nothing will be in the error value. I've tried redefining the error value to be a string in the interface, but it does the same thing. However, I don't recall if it did anything in C++. At any rate, there needs to be some error checking after the matrix is opened to ensure that it actually has opened, else the program will crash (and it doesn't do a normal crash).
Also ensure that the project is setup with the character set of "Not Set" as opposed to Unicode, which seems to be a default in MS Visual C++ Express Edition.
The main application is fairly simple and just opens the matrix and outputs the number of tables and zones to the screen.
using namespace std;
int _tmain(int argc, _TCHAR* argv)
// Open the matrix
// Get number of tables in the matrix
int nMats = MatReaderGetNumMats(matrixState);
// Get number of zones in the matrix
int nZones = MatReaderGetNumZones(matrixState);
// Output to screen
cout << "File " << argv << endl;
cout << "Number of Tables....." << nMats << endl;
cout << "Number of Zones......" << nZones << endl;
// Close the matrix
cout << "Matrix Closed." << endl;
cout << "Press any key to close" << endl; char tmp; cin >> tmp;