Table of Contents

How to write an export tool

An export tool (export) makes it possible to export a given step of a simulation history into a file with a given format.

From the given step, it is also possible to write information concerning the whole scenario from the root step to the given referent step.

Exports can be called from the Capsis user interface: Step contextual menu > Export > choose an export, choose an output file, validate. They also can be called from Capsis scripts to be run during a background simulation with this kind of syntax:

// Export a given simulation step to a fileName
GenExport e = new GenExport ();
e.initExport (model, step);
e.save (fileName);

A simple example : the Genloader export

Reminder: an entry must be added in the etc/extension.list of Capsis otherwise the extension will not be found by the ExtensionManager.

...
douglas.model.DouglasInventoryLoader=enabled
...

Note: this can be done by Capsis without editing the file, by using the 'search extensions' feature from the command line once the extension written:

capsis -se

Step by step detailled comments

The code of this export is presented in the commented blocks below. The complete code can be found at the bottom of this document in case you would like to copy it to make a new intervener.

package genloader.extension.ioformat;
 
import genloader.model.GenModel;
import genloader.model.GenStand;
import genloader.model.GenTree;
 
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
 
import jeeb.lib.util.Import;
import jeeb.lib.util.Log;
import jeeb.lib.util.Record;
import jeeb.lib.util.Translator;
import capsis.kernel.GModel;
import capsis.kernel.GScene;
import capsis.util.GTreeIdComparator;
import capsis.util.StandRecordSet;

The export is part of the Genloader module. This module just loads inventories to watch them in the Capsis viewers.

/**
 * GenExport exports a GenScene to a file.
 * 
 * @author F. de Coligny - may 2011
 */
public class GenExport extends StandRecordSet {
 
	// Extension properties
	static public String NAME = Translator.swap ("GenExport");
	static public String AUTHOR = "F. de Coligny";
	static public String VERSION = "1.0";
	static public String DESCRIPTION = Translator.swap ("GenExport.description");
 
	static {
		Translator.addBundle("genloader.extension.ioformat.GenExport");
	}
 
 
	// A tree line in the file
	@Import
	static public class TreeLine extends Record {
 
		public TreeLine () {
			super ();
		}
 
		public TreeLine (String line) throws Exception {
			super (line);
		}
 
		// public String getSeparator () {return ";";} // to change default "\t" separator
		public int id; // unique in the scene
		public int age; // years
		public double x;
		public double y;
		public double z;
		public double dbh; // m.
		public double height; // cm.
		public double crownBaseHeight; // m.
		public double crownRadius; // m.
		public int stateCode; // can match with colors in viewers
		public char shapeCode; // 'c' cone, 'e' ellipse...
		public float transparency; // 0.0 (opaque) to 1.0 (transparent)
	}

The export extends StandRecordSet (needed for exports).

The exports need 4 administrative constants: NAME, AUTHOR, VERSION, DESCRIPTION. NAME and DESCRIPTION must go through the Translator.

The Translator is told to load a translation bundle for this class (the language was chosen by the user at Capsis launch time). These translation may be found in the required files GenExport_en.properties and GenExport_fr.properties.

Example for the english GenExport_en.properties file:

## GenExport labels - English

GenExport = GenLoader Export
GenExport.description = An export for the GenLoader module

The TreeLine inner class (such inner classes are optional) describes the format of a line in the output file, there will be one line per trees in the exported scene.

	/**
	 * Constructor
	 */
	public GenExport () {
		super ();
		// Do not write the standard header lines in the output file
		setHeaderEnabled (false);
	}
 
	/**
	 * Extension dynamic compatibility mechanism. This matchWith method checks if the extension can
	 * deal (i.e. is compatible) with the referent.
	 */
	static public boolean matchWith (Object referent) {
		try {
			if (!(referent instanceof GenModel)) { return false; }
 
		} catch (Exception e) {
			Log.println (Log.ERROR, "GenExport.matchWith ()", "Error in matchWith () (returned false)", e);
			return false;
		}
 
		return true;
	}

The constructor is very simple, it calls the superclass constructor then disables the Capsis standard headers (optional). This header is several lines heigh and may be not needed in some cases.

The matchWith () method is there for built-in compatibility check. It will tell it's compatible only with the GenModel (model class of the GenLoader module).

	/**
	 * Export: turns the given Scene into a collection of records
	 * In script mode, save (fileName) must be called after.
	 */
	@Override
	public void createRecordSet (GScene s) throws Exception {
		GenStand scene = (GenStand) s;
		super.createRecordSet (scene); // deals with RecordSet's source
 
		// 1. Custom headers
		add (new CommentRecord ("Genloader scene export (GenExport) at "+new Date ()));
		add (new EmptyRecord ());
 
		add (new CommentRecord ("Trees"));
		add (new FreeRecord ("Scene at date "+scene.getDate ()+" scene area(m2) "+scene.getArea ()));
 
		add (new EmptyRecord ());
		add (new KeyRecord ("origin", ""+scene.getOrigin ()));
		add (new KeyRecord ("xSize", ""+scene.getXSize ()));
		add (new KeyRecord ("ySize", ""+scene.getYSize ()));
 
		// 2. TreeRecords
		add (new EmptyRecord ());
		add (new CommentRecord ("Trees"));
		add (new CommentRecord ("id	age	x	y	z	dbh	height	crownBaseHeight	crownRadius	stateCode	shapeCode	transparency"));
		add (new EmptyRecord ());
 
		// Sort the trees on their ids
		Set sortedTrees = new TreeSet (new GTreeIdComparator ());
		sortedTrees.addAll (scene.getTrees ());
 
		for (Iterator i = sortedTrees.iterator (); i.hasNext ();) {
			GenTree t = (GenTree) i.next ();
 
			TreeLine r = new TreeLine ();
 
			r.id = t.getId ();
			r.age = t.getAge ();
			r.x = t.getX ();
			r.y = t.getY ();
			r.z = t.getZ ();
			r.dbh = t.getDbh ();
			r.height = t.getHeight ();
			r.crownBaseHeight = t.getCrownBaseHeight ();
			r.crownRadius = t.getCrownRadius ();
			r.stateCode = t.getStateCode ();
			r.shapeCode = t.getShapeCode ();
			r.transparency = t.getTransparency ();
			add (r);
		}
 
	}

The createRecordSet () method does the export job: it turns the given scene into a number of 'Records'.

These records may be instances of:

All these records are directly added in the export (which extends ArrayList), the order of insertion will be kept when they are written in the file later.

	/**
	 * Importation is not implemented here
	 */
	@Override
	public GScene load (GModel m) throws Exception {
		return null;
	}

The load () method is not used in this export (exports may also import).

The resulting file

The following file was built by running the GenExport on the root step of a Genloader simulation with the input simulation file:

capsis4/data/genloader/biomecanicseol.csv
# Genloader scene export (GenExport) at Mon May 30 17:11:56 CEST 2011

# Trees
Scene at date 0 scene area(m2) 11968.356999282842

origin = (0,0,0)
xSize = 109.3499984741211
ySize = 109.44999694824219

# Trees
# id	age	x	y	z	dbh	height	crownBaseHeight	crownRadius	stateCode	shapeCode	transparency

1	10	25.1299991607666	109.20999908447266	0.0	15.449999809265137	22.5	12.1	4.1	0	e	0.0
2	10	13.109999656677246	101.37999725341797	0.0	17.950000762939453	17.829999923706055	11.34	4.4	0	e	0.0
3	10	29.309999465942383	99.04000091552734	0.0	13.579999923706055	14.5	10.3	2.5	0	e	0.0
4	10	24.649999618530273	99.83000183105469	0.0	23.020000457763672	23.979999542236328	16.73	4.85	0	e	0.0
5	10	21.700000762939453	96.16999816894531	0.0	21.81999969482422	28.5	20.22	4.85	0	e	0.0
6	10	28.59000015258789	95.12999725341797	0.0	16.139999389648438	26.329999923706055	16.91	3.9	0	e	0.0
7	10	25.34000015258789	85.51000213623047	0.0	21.43000030517578	29.600000381469727	12.5	5.0	0	e	0.0
8	10	14.350000381469727	50.619998931884766	0.0	12.760000228881836	16.799999237060547	9.5	3.4	0	e	0.0
9	10	22.770000457763672	51.58000183105469	0.0	29.110000610351562	24.5	12.4	4.0	0	e	0.0
10	10	20.3799991607666	34.81999969482422	0.0	10.579999923706055	13.5	11.5	1.8	0	e	0.0
11	10	27.979999542236328	32.5	0.0	39.220001220703125	30.399999618530273	10.1	8.8	0	e	0.0
12	10	14.119999885559082	20.860000610351562	0.0	13.5	18.700000762939453	11.1	1.9	0	e	0.0
13	10	17.780000686645508	16.239999771118164	0.0	29.760000228881836	27.229999542236328	14.77	8.4	0	e	0.0
14	10	26.719999313354492	18.790000915527344	0.0	60.959999084472656	53.70000076293945	21.7	13.4	0	e	0.0
15	10	20.549999237060547	10.75	0.0	13.670000076293945	15.5	10.4	3.1	0	e	0.0
16	10	28.100000381469727	4.380000114440918	0.0	10.699999809265137	13.220000267028809	5.77	3.0	0	e	0.0
17	10	8.869999885559082	25.260000228881836	0.0	23.260000228881836	23.200000762939453	14.3	4.15	0	e	0.0
18	10	1.4900000095367432	65.9800033569336	0.0	81.08999633789062	31.0	21.7	9.7	0	e	0.0
19	10	2.5	102.0	0.0	11.520000457763672	17.09000015258789	12.02	2.85	0	e	0.0
20	10	0.44999998807907104	59.599998474121094	0.0	14.550000190734863	18.0	12.2	2.5	0	e	0.0
21	10	30.290000915527344	36.4900016784668	0.0	11.65999984741211	24.100000381469727	15.6	2.1	0	e	0.0
22	10	33.91999816894531	77.41999816894531	0.0	13.710000038146973	17.399999618530273	12.1	0.95	0	e	0.0
23	10	32.4900016784668	98.6500015258789	0.0	26.829999923706055	26.0	17.0	4.1	0	e	0.0
24	10	39.849998474121094	101.6500015258789	0.0	24.1200008392334	28.299999237060547	11.5	4.85	0	e	0.0
25	10	47.75	7.340000152587891	0.0	11.210000038146973	10.699999809265137	7.3	1.55	0	e	0.0
26	10	41.849998474121094	15.970000267028809	0.0	57.4900016784668	39.0	30.4	9.45	0	e	0.0
27	10	49.68000030517578	17.309999465942383	0.0	28.989999771118164	24.700000762939453	16.9	2.7	0	e	0.0
28	10	46.11000061035156	75.48999786376953	0.0	16.110000610351562	19.700000762939453	14.0	2.7	0	e	0.0
29	10	47.119998931884766	74.47000122070312	0.0	10.789999961853027	15.0	11.0	2.8	0	e	0.0
30	10	49.52000045776367	80.11000061035156	0.0	24.729999542236328	23.5	15.9	4.5	0	e	0.0
31	10	49.040000915527344	81.62999725341797	0.0	23.649999618530273	22.899999618530273	16.5	2.3	0	e	0.0
32	10	47.470001220703125	80.26000213623047	0.0	15.739999771118164	19.700000762939453	13.02	2.65	0	e	0.0
33	10	43.09000015258789	87.69000244140625	0.0	22.520000457763672	23.100000381469727	17.5	1.8	0	e	0.0
34	10	43.619998931884766	91.13999938964844	0.0	15.010000228881836	18.020000457763672	10.99	3.95	0	e	0.0
35	10	49.900001525878906	107.30000305175781	0.0	23.579999923706055	28.959999084472656	18.95	3.7	0	e	0.0
36	10	50.619998931884766	19.1200008392334	0.0	36.310001373291016	27.0	23.3	5.55	0	e	0.0
37	10	54.560001373291016	72.0	0.0	18.739999771118164	18.0	14.5	1.65	0	e	0.0
38	10	54.25	74.33000183105469	0.0	9.920000076293945	11.510000228881836	9.05	3.7	0	e	0.0
39	10	50.86000061035156	88.33000183105469	0.0	18.809999465942383	22.100000381469727	15.7	3.65	0	e	0.0
40	10	56.709999084472656	88.11000061035156	0.0	41.91999816894531	34.95000076293945	15.15	8.0	0	e	0.0
41	10	52.29999923706055	94.55999755859375	0.0	40.7400016784668	25.239999771118164	16.87	6.3	0	e	0.0
42	10	57.709999084472656	92.80999755859375	0.0	36.060001373291016	27.09000015258789	15.2	5.95	0	e	0.0
43	10	58.63999938964844	96.56999969482422	0.0	19.25	18.299999237060547	16.22	4.45	0	e	0.0
44	10	57.099998474121094	99.45999908447266	0.0	15.050000190734863	16.299999237060547	11.93	3.65	0	e	0.0
45	10	59.349998474121094	101.75	0.0	12.359999656677246	9.5	3.5	1.6	0	e	0.0
46	10	58.75	104.5999984741211	0.0	31.969999313354492	24.200000762939453	16.22	6.1	0	e	0.0
47	10	50.5	105.80000305175781	0.0	23.43000030517578	21.200000762939453	16.5	5.35	0	e	0.0
48	10	50.29999923706055	107.80000305175781	0.0	22.639999389648438	21.399999618530273	12.5	2.95	0	e	0.0
49	10	69.56999969482422	14.279999732971191	0.0	62.349998474121094	33.79999923706055	29.4	7.85	0	e	0.0
50	10	64.69999694824219	14.630000114440918	0.0	22.40999984741211	22.100000381469727	16.58	4.55	0	e	0.0
51	10	63.119998931884766	22.1200008392334	0.0	26.850000381469727	22.799999237060547	18.4	2.75	0	e	0.0
52	10	64.19000244140625	35.86000061035156	0.0	21.229999542236328	31.40999984741211	27.37	2.9	0	e	0.0
53	10	64.41000366210938	42.709999084472656	0.0	29.34000015258789	22.299999237060547	12.2	5.2	0	e	0.0
54	10	60.56999969482422	40.97999954223633	0.0	24.969999313354492	27.0	20.2	4.45	0	e	0.0
55	10	61.79999923706055	55.54999923706055	0.0	10.140000343322754	15.180000305175781	9.82	2.75	0	e	0.0
56	10	60.70000076293945	63.34000015258789	0.0	13.4399995803833	13.600000381469727	9.7	1.55	0	e	0.0
57	10	66.5199966430664	75.8499984741211	0.0	10.069999694824219	15.319999694824219	9.71	2.75	0	e	0.0
58	10	64.66999816894531	79.31999969482422	0.0	16.700000762939453	20.420000076293945	14.81	3.9	0	e	0.0
59	10	69.52999877929688	83.44999694824219	0.0	28.700000762939453	28.799999237060547	24.3	4.9	0	e	0.0
60	10	76.61000061035156	2.369999885559082	0.0	13.140000343322754	18.68000030517578	11.52	3.35	0	e	0.0
61	10	76.80999755859375	35.31999969482422	0.0	45.099998474121094	36.5	21.92	6.95	0	e	0.0
62	10	71.6500015258789	39.63999938964844	0.0	59.38999938964844	39.75	30.07	5.9	0	e	0.0
63	10	76.72000122070312	53.95000076293945	0.0	13.6899995803833	17.0	10.3	2.3	0	e	0.0
64	10	73.91999816894531	53.68000030517578	0.0	12.279999732971191	18.260000228881836	12.43	1.95	0	e	0.0
65	10	76.79000091552734	62.220001220703125	0.0	11.649999618530273	14.029999732971191	9.78	1.65	0	e	0.0
66	10	73.80000305175781	70.30000305175781	0.0	17.979999542236328	21.0	11.0	2.6	0	e	0.0
67	10	76.01000213623047	84.0199966430664	0.0	22.239999771118164	18.899999618530273	14.5	4.1	0	e	0.0
68	10	85.54000091552734	15.40999984741211	0.0	56.36000061035156	36.29999923706055	24.39	7.9	0	e	0.0
69	10	83.41000366210938	15.979999542236328	0.0	35.5099983215332	26.219999313354492	18.47	8.2	0	e	0.0
70	10	85.0199966430664	25.34000015258789	0.0	16.540000915527344	17.899999618530273	14.2	3.3	0	e	0.0
71	10	83.1500015258789	36.08000183105469	0.0	47.290000915527344	33.0	28.5	9.8	0	e	0.0
72	10	84.51000213623047	48.369998931884766	0.0	9.859999656677246	11.800000190734863	7.4	1.5	0	e	0.0
73	10	85.7699966430664	63.95000076293945	0.0	13.069999694824219	19.40999984741211	15.76	3.15	0	e	0.0
74	10	88.5	64.0999984741211	0.0	15.989999771118164	19.700000762939453	13.2	3.05	0	e	0.0
75	10	95.30999755859375	24.0	0.0	82.70999908447266	44.0	30.0	9.4	0	e	0.0
76	10	93.16000366210938	37.040000915527344	0.0	20.860000610351562	25.270000457763672	17.64	3.0	0	e	0.0
77	10	91.26000213623047	44.400001525878906	0.0	22.739999771118164	20.75	7.23	2.5	0	e	0.0
78	10	92.9800033569336	47.36000061035156	0.0	37.65999984741211	29.399999618530273	23.3	3.45	0	e	0.0
79	10	94.0199966430664	50.369998931884766	0.0	47.56999969482422	29.100000381469727	18.58	15.05	0	e	0.0
80	10	90.20999908447266	61.650001525878906	0.0	15.229999542236328	22.600000381469727	17.0	3.3	0	e	0.0
81	10	109.19999694824219	5.5	0.0	78.80999755859375	32.599998474121094	24.0	15.1	0	e	0.0
82	10	105.44999694824219	4.849999904632568	0.0	17.459999084472656	22.200000762939453	14.4	3.0	0	e	0.0
83	10	100.44999694824219	2.8499999046325684	0.0	11.829999923706055	10.399999618530273	5.2	7.45	0	e	0.0
84	10	106.0	19.450000762939453	0.0	84.88999938964844	40.5	30.0	11.6	0	e	0.0
85	10	101.5	34.75	0.0	75.0999984741211	33.29999923706055	20.0	9.8	0	e	0.0
86	10	104.80000305175781	38.849998474121094	0.0	37.349998474121094	26.5	14.2	9.4	0	e	0.0
87	10	109.0999984741211	47.20000076293945	0.0	10.119999885559082	12.300000190734863	7.5	0.7	0	e	0.0
88	10	103.44999694824219	54.04999923706055	0.0	12.470000267028809	15.899999618530273	12.2	4.1	0	e	0.0
89	10	108.94999694824219	59.45000076293945	0.0	9.800000190734863	15.100000381469727	6.2	1.15	0	e	0.0
90	10	109.3499984741211	64.19999694824219	0.0	15.0600004196167	18.700000762939453	15.5	4.5	0	e	0.0
91	10	100.1500015258789	109.44999694824219	0.0	10.470000267028809	12.800000190734863	7.3	1.6	0	e	0.0
92	10	108.0999984741211	105.9000015258789	0.0	93.30000305175781	35.5	23.6	12.65	0	e	0.0

The complete code of the GenExport example

package genloader.extension.ioformat;
 
import genloader.model.GenModel;
import genloader.model.GenStand;
import genloader.model.GenTree;
 
import java.util.Date;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
 
import jeeb.lib.util.Import;
import jeeb.lib.util.Log;
import jeeb.lib.util.Record;
import jeeb.lib.util.Translator;
import capsis.kernel.GModel;
import capsis.kernel.GScene;
import capsis.util.GTreeIdComparator;
import capsis.util.StandRecordSet;
 
/**
 * GenExport exports a GenScene to a file.
 * 
 * @author F. de Coligny - may 2011
 */
public class GenExport extends StandRecordSet {
 
	// Extension properties
	static public String NAME = Translator.swap ("GenExport");
	static public String AUTHOR = "F. de Coligny";
	static public String VERSION = "1.0";
	static public String DESCRIPTION = Translator.swap ("GenExport.description");
 
	static {
		Translator.addBundle("genloader.extension.ioformat.GenExport");
	}
 
 
	// A tree line in the file
	@Import
	static public class TreeLine extends Record {
 
		public TreeLine () {
			super ();
		}
 
		public TreeLine (String line) throws Exception {
			super (line);
		}
 
		// public String getSeparator () {return ";";} // to change default "\t" separator
		public int id; // unique in the scene
		public int age; // years
		public double x;
		public double y;
		public double z;
		public double dbh; // m.
		public double height; // cm.
		public double crownBaseHeight; // m.
		public double crownRadius; // m.
		public int stateCode; // can match with colors in viewers
		public char shapeCode; // 'c' cone, 'e' ellipse...
		public float transparency; // 0.0 (opaque) to 1.0 (transparent)
	}
 
 
	/**
	 * Constructor
	 */
	public GenExport () {
		super ();
		// Do not write the standard header lines in the output file
		setHeaderEnabled (false);
	}
 
	/**
	 * Extension dynamic compatibility mechanism. This matchWith method checks if the extension can
	 * deal (i.e. is compatible) with the referent.
	 */
	static public boolean matchWith (Object referent) {
		try {
			if (!(referent instanceof GenModel)) { return false; }
 
		} catch (Exception e) {
			Log.println (Log.ERROR, "GenExport.matchWith ()", "Error in matchWith () (returned false)", e);
			return false;
		}
 
		return true;
	}
 
	/**
	 * Export: turns the given Scene into a collection of records
	 * In script mode, save (fileName) must be called after.
	 */
	@Override
	public void createRecordSet (GScene s) throws Exception {
		GenStand scene = (GenStand) s;
		super.createRecordSet (scene); // deals with RecordSet's source
 
		// 1. Custom headers
		add (new CommentRecord ("Genloader scene export (GenExport) at "+new Date ()));
		add (new EmptyRecord ());
 
		add (new CommentRecord ("Trees"));
		add (new FreeRecord ("Scene at date "+scene.getDate ()+" scene area(m2) "+scene.getArea ()));
 
		add (new EmptyRecord ());
		add (new KeyRecord ("origin", ""+scene.getOrigin ()));
		add (new KeyRecord ("xSize", ""+scene.getXSize ()));
		add (new KeyRecord ("ySize", ""+scene.getYSize ()));
 
		// 2. TreeRecords
		add (new EmptyRecord ());
		add (new CommentRecord ("Trees"));
		add (new CommentRecord ("id	age	x	y	z	dbh	height	crownBaseHeight	crownRadius	stateCode	shapeCode	transparency"));
		add (new EmptyRecord ());
 
		// Sort the trees on their ids
		Set sortedTrees = new TreeSet (new GTreeIdComparator ());
		sortedTrees.addAll (scene.getTrees ());
 
		for (Iterator i = sortedTrees.iterator (); i.hasNext ();) {
			GenTree t = (GenTree) i.next ();
 
			TreeLine r = new TreeLine ();
 
			r.id = t.getId ();
			r.age = t.getAge ();
			r.x = t.getX ();
			r.y = t.getY ();
			r.z = t.getZ ();
			r.dbh = t.getDbh ();
			r.height = t.getHeight ();
			r.crownBaseHeight = t.getCrownBaseHeight ();
			r.crownRadius = t.getCrownRadius ();
			r.stateCode = t.getStateCode ();
			r.shapeCode = t.getShapeCode ();
			r.transparency = t.getTransparency ();
			add (r);
		}
 
	}
 
	/**
	 * Importation is not implemented here
	 */
	@Override
	public GScene load (GModel m) throws Exception {
		return null;
	}
 
 
}