Blog from October, 2007

Try catch(all)

When a program runs in release mode you usually wanna catch all errors. When it doesn't you just wanna let it crash.
To make a function depend on debug vs release you can use 2 methods:

Using precompile statements

#if DEBUG
  // do something for debug 
#else
  // do something else
#endif

Or you can make a method depend on release vs debug using a conditional.

[Conditional("RELEASE") ]

In general try catch all is considered bad practice.

How to tell DelftShell to load only specific plugins

Currently DelftShell uses .NET application configuration options defined in DelftShell.Loader.exe.config. Actually these options are copied from app.config in the project sources, VS does it automatically during compilation.

Additionally there is a way to define user-specific settings, see for example DelftShell/Properties/Settings.settings file.

When DelftShell is started from the VS - it loads all plugins from the following folder:

apps\DelftShell\modules\DelftShell.Loader\bin\
   plugins\
      Habitat\
         DelfShell.Plugins.Habitat.dll
      Verkenner\
         DelfShell.Plugins.Verkenner.dll
      Sobek\
         DelfShell.Plugins.Sobek.dll
      ...
   Debug\
      DelftShell.Loader.exe
      DelftShell.Loader.exe.config ....... application settings file (XML)
      DelftShell.dll
      DelftTools.Core.dll
      DelftTools.Gui.dll
      ...
   Release\
      ...

User settings file is generated automatically at each exit of DelftShell:

C:\Documents and Settings\donchyt\Local Settings\Application Data\Delft_Hydraulics\DelftShell.Loader.exe...\1.0.0.0\user.config

If you want to load only specific plugin - put the following option there:

<setting name="loadedPluginsFilterExpression" serializeAs="String">
     <value>Habitat</value>
</setting>

It can contain plugin name or any other .NET Regular Expression.

Native plugin RGFGrid and DelftShell

In a previous version the loading of native plugins from managed code was accomplished via special test classes.
It is now also possible to load the plugin from DelftShell.
This is a first hack, the classes in NativeGisGuiDelftShellPluginGui will be restructured
Known issues:

  • Activation does not work correctly (eg. mousewheel and keyboard shortcuts will not work as expected)
  • integration of toolbars and menu's
  • multiple loading of the same plugin (2x rgfgrid) will cause a crash
  • unloading will cause a crash (fix is known, but not implemented)
  • paths to native plugins hardcoded
  • native plugins with modal dialogs do not properly disable their parent (see image)
    ...

RGFGRID coordinates

Most data values that we use in our models are defined at some (x,y,z) locations. For the time being we will focus on the horizontal coordinates only. These coordinates are always specified in some coordinate system, such as WGS84, Rijksdriehoek, some UTM projection, etc. At this moment our software systems do not know about these different coordinate systems in general, only Delft3D distinguishes between spherical and cartesian coordinates. Where the former is generally asumed to be equivalent to WGS84 (coordinates specified in degrees longitude and latitude) while the latter is a general projection on some local coordinate space with perpendicular x and y directions (coordinates measured along these axes in metres). In several cases one would like to perform coordinate transformations on sets of coordinates:

  1. dataset was provided in coordinate system A, but needs to be used in conjunction with a model in system B
  2. dataset is given in coordinate system A whereas visualisation is using system B
  3. dataset is given in (cartesian) coordinate system A whereas file format requires storage in system B (e.g. WGS84 in case of NetCDF CF-conventions)
  4. a schematisation in coordinate system A needs to be coupled to a schematisation in coordinate system B

In all cases it is important to have more information about the coordinate systems than it being spheric or cartesian. This information needs to be stored in a standardised way for automated use by the software components that will process or display the data. For this purpose we need to store for each georeferenced dataset which coordinate system it uses as reference. For all numerical schematisations this starts by storing the coordinate system of the initial network, grid or mesh.

So, let's start with the source of a Delft3D simulation, the RGFGRID file *.grd.

How do we project the grid data to the screen?

Currently the RGFGRID file format contains information about the kind of the data.
This can be either cartesian or spheric. The spheric option implies that the WGS84 is used (R=6378137.0). WGS84 is only valid until 2010.
The cartesian implies that a local x y is used, so the distance betweeen two points can be determined with Pythagoras (ds^2 = dx^2 + dy^2). The center is not specified. If the ArcGIS frontend is used the source reference system for a new grid is given by ArcGIS.

The (display) target can be specified as spheric or cartesian. The display projection is not relevant for the Delft3D model and is a transient property of the visualisation only. In other cases (as indicated above) the conversion of the data is more persistent (e.g. file storage).

We're trying to improve this part of the software by

  • Using gdal/ogr for doing the reprojection calculation
  • Using the EPSG for standardization of the projections
  • Using WKT as exchange format for projection information
  • Making a udig like projection selection dialog.

This will allow users to explicitly define which information is or is not available about the coordinate system and more easily select which coordinate system to use.

The sources are set up under http://svn/repos/gis-plugins.
Relevant utils:
http://fwtools.maptools.org/ compiled binary under windows
http://www.gdal.org source for gdal information (get package gdal-dev to develop under linux)

NUnit Ignore - use carefully!

IgnoreAttribute (NUnit 2.0)

The ignore attribute is an attribute to not run a test or test fixture for a period of time. The person marks either a Test or a TestFixture with the Ignore Attribute. The running program sees the attribute and does not run the test or tests. The progress bar will turn yellow if a test is not run and the test will be mentioned in the reports that it was not run.

This feature should be used to temporarily not run a test or fixture. This is a better mechanism than commenting out the test or renaming methods, since the tests will be compiled with the rest of the code and there is an indication at run time that a test is not being run. This insures that tests will not be forgotten.

Native plugin RGFGrid and managed code

In order to get the native plugins available in Delft Shell a number of abstract classes has been implemented in managed .NET code. In a simple test the native RGFGrid.dll is loaded that uses managed implementations of AbstractCanvas, AbstractCanvasWindow and AbstractCanvasListener.

Some problems still have to be solved - Qt windows calls, minor drawing differences, etc. - but this is a maior proof of concept.

Calling a ArcGIS plugin from managed code via late binding

In the sandbox a demo project has been added that calls an ARCGIS plugin via late binding

please refer to delft-tools\sandbox\ArcGisProjects\DesktopExtensions 

The relevant code is

public class ArcViewOnlyExtension : IExtension, IExtensionConfig
{
   void ExecuteContextArcMfe_Delft3d(object sender, EventArgs e)
   {{
      // Note this code will only work with plugins that implement the PluginsExtPublicCmd
      // COM object.
      COMObjectLateBinding cnet = new COMObjectLateBinding("ArcMfe_Delft3d.PluginsExtPublicCmd");
      cnet.Execute("executeCmd", new object[] {{ "een opdrachtje", "en de aansturing" });
   }
   ...
}

a simple wrapper class COMObjectLateBinding is used.

We have a green light!

Some failing tests were fixed for DelftShell / DelftTools. Let's keep it like this from now.

Quote from Martin Fowler's article about Continuous Integration:

In a Continuous Integration environment you should never have a failed integration build stay failed for long. A good team should have many correct builds a day. Bad builds do occur from time to time, but should be quickly fixed.

The gisfrontend plugin is mostly platform independent. The only windows specific part I found so far was

        void add(const char* libraryPath, const char* apiSymbolName) {
                HMODULE libraryAddress = LoadLibrary(libraryPath);
                assert(libraryAddress != NULL);

                AbstractGisPlugin* (*fp)();
                fp = (AbstractGisPlugin* (*)())GetProcAddress((HMODULE)libraryAddress, apiSymbolN\
ame);
                assert(fp != NULL);

                AbstractGisPlugin* plugin = fp();
                plugins.push_back(plugin);
        }

This loads the dynamic library. This is done with the dlopen calls.

References

http://www.ibm.com/developerworks/aix/library/au-porting/
http://www.faqs.org/docs/Linux-HOWTO/Program-Library-HOWTO.html