001: /*
002: * This file is part of the GeOxygene project source files.
003: *
004: * GeOxygene aims at providing an open framework which implements OGC/ISO specifications for
005: * the development and deployment of geographic (GIS) applications. It is a open source
006: * contribution of the COGIT laboratory at the Institut Géographique National (the French
007: * National Mapping Agency).
008: *
009: * See: http://oxygene-project.sourceforge.net
010: *
011: * Copyright (C) 2005 Institut Géographique National
012: *
013: * This library is free software; you can redistribute it and/or modify it under the terms
014: * of the GNU Lesser General Public License as published by the Free Software Foundation;
015: * either version 2.1 of the License, or any later version.
016: *
017: * This library is distributed in the hope that it will be useful, but WITHOUT ANY
018: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
019: * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
020: *
021: * You should have received a copy of the GNU Lesser General Public License along with
022: * this library (see file LICENSE if present); if not, write to the Free Software
023: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024: *
025: */
026:
027: package fr.ign.cogit.geoxygene.util.algo;
028:
029: import java.awt.Color;
030: import java.io.File;
031: import java.io.FileOutputStream;
032: import java.io.OutputStream;
033: import java.io.PrintStream;
034: import java.io.UnsupportedEncodingException;
035: import java.lang.reflect.InvocationTargetException;
036: import java.lang.reflect.Method;
037: import java.text.DecimalFormat;
038: import java.util.StringTokenizer;
039:
040: import com.vividsolutions.jts.geom.Coordinate;
041: import com.vividsolutions.jts.geom.CoordinateSequence;
042: import com.vividsolutions.jts.geom.DefaultCoordinateSequenceFactory;
043: import com.vividsolutions.jts.geom.TopologyException;
044:
045: import fr.ign.cogit.geoxygene.datatools.Geodatabase;
046: import fr.ign.cogit.geoxygene.datatools.ojb.GeodatabaseOjbFactory; //import fr.ign.cogit.geoxygene.datatools.oracle.*;
047: import fr.ign.cogit.geoxygene.feature.FT_FeatureCollection;
048: import fr.ign.cogit.geoxygene.spatial.coordgeom.DirectPosition;
049: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Envelope;
050: import fr.ign.cogit.geoxygene.spatial.coordgeom.GM_Polygon;
051: import fr.ign.cogit.geoxygene.spatial.geomaggr.GM_Aggregate;
052: import fr.ign.cogit.geoxygene.spatial.geomaggr.GM_MultiSurface;
053: import fr.ign.cogit.geoxygene.spatial.geomprim.GM_Point;
054: import fr.ign.cogit.geoxygene.spatial.geomroot.GM_Object;
055: import fr.ign.cogit.geoxygene.util.conversion.ImgUtil;
056: import fr.ign.cogit.geoxygene.util.conversion.JtsGeOxygene;
057:
058: /**
059: * Test et comparaison des methodes geometriques de differentes bibliotheques.
060: * Sont prevues : Oracle, Jts, Geos.
061: * On peut facilement completer le test par de nouvelles bibliotheques
062: * en creant une nouvelle classe fille de GeomAlgorithms
063: * et en l'appelant dans cette application.
064: * Le programme genere des images et des fichiers SVG compresses.
065: * Un fichier de comparaison des temps de calcul entre les differentes bibliotheques est aussi genere.
066: * On charge un nombre progressif d'objets, en utilisant le rectangle englobant (enveloppe) des couches testees
067: * et en faisant varier par un facteur la taille de cette enveloppe (variables a regler au debut du code).
068: * A l'aide d'une boucle, on charge progressivement de plus en plus d'objets.
069: *
070: * ARNAUD 12 juillet 2005 : mise en commentaire de ce qui se rapporte à Oracle
071: * pour isoler la compilation. A décommenter pour utiliser Oracle.
072: *
073: * @author Thierry Badard, Arnaud Braun & Christophe Pele
074: * @version 1.1
075: *
076: */
077:
078: public class CompareLib {
079:
080: private static IndentedPrintStream out;
081: private static PrintStream err = System.err;
082:
083: private Geodatabase db;
084:
085: // Alias de Connection a Oracle (dans le fichier de mapping repository_database.xml)
086: private String ORACLE_ALIAS = "ORACLE_ALIAS";
087:
088: // classes a charger
089: private Class featClass1;
090: private Class featClass2;
091:
092: // emprise maximale des geometries, recuperees dans les metadonnees du chargement
093: private GM_Envelope baseEnvelope;
094:
095: // les bibliotheques a tester
096: private GeomAlgorithms jts;
097: private GeomAlgorithms oracle;
098: private GeomAlgorithms geos;
099:
100: // les resultats des operateurs geometriques
101: private Object resultJts;
102: private Object resultOracle;
103: private Object resultGeos;
104:
105: /* ############################################################# */
106: /* variable permettant de parametrer le test, a initialiser ici */
107: /* ############################################################# */
108:
109: /* liste des algos a tester */
110: private String[] algorithmsName = new String[] { "buffer10",
111: "convexHull", "centroid", "intersection", "union",
112: "difference", "symDifference", "length", "area",
113: "distance", "equals", "contains", "intersects" };
114:
115: /* Les noms de classes de feature a charger */
116: private String featClassName1 = "geoschema.feature.Topo_bati_extrait5";
117: private String featClassName2 = "geoschema.feature.Topo_bati_extrait5_translate";
118:
119: /* agregats geometriques issus du chargement des classes ;
120: * definir ici si c'est des GM_MultiCurve ou des GM_MultiSurface */
121: private GM_Aggregate geom1 = new GM_MultiSurface(); /*new GM_MultiCurve(); */
122: private GM_Aggregate geom2 = new GM_MultiSurface(); /*new GM_MultiCurve(); */
123:
124: /* Le repertoire de sauvegarde des resultats */
125: private String path = "/home/users/braun/testJtsOracle";
126:
127: /* definit les bibliotheques qu'on teste */
128: private boolean testJts = true;
129: private boolean testOracle = true;
130: private boolean testGeos = false;
131:
132: /* facteurs pour la boucle faisant varier la taille de l'enveloppe definissant les objets a charger */
133: private double min = 0.2;
134: private double max = 1.0;
135: private double step = 0.2;
136:
137: /* indique si on sauve les fichiers SVGZ et les images au format .png*/
138: private boolean saveSvg = true;
139: private boolean saveImage = false;
140:
141: // ########################################################################################
142: public CompareLib() {
143: out = new IndentedPrintStream(System.out);
144: out.println("Begin!");
145:
146: out.print("connecting database ... ");
147: db = GeodatabaseOjbFactory.newInstance(ORACLE_ALIAS);
148: out.println("OK");
149:
150: if (testJts)
151: jts = new JtsAlgorithms();
152: // if (testOracle) oracle=new OracleAlgorithms(db,0.0000000005);
153: if (testGeos)
154: geos = new GeosAlgorithms();
155:
156: try {
157: featClass1 = Class.forName(featClassName1);
158: featClass2 = Class.forName(featClassName2);
159: } catch (Exception e) {
160: err.println("## Classes geographiques non trouvées ##");
161: System.exit(0);
162: }
163: out.println("test class 1 : " + featClass1.getName());
164: out.println("test class 2 : " + featClass2.getName());
165:
166: out.println("Computing envelope...");
167:
168: try {
169: GM_Envelope baseEnvelope1 = db.getMetadata(featClass1)
170: .getEnvelope();
171: GM_Envelope baseEnvelope2 = db.getMetadata(featClass2)
172: .getEnvelope();
173: // on prend l'enveloppe maximale des deux enveloppes
174: baseEnvelope1.expand(baseEnvelope2);
175: baseEnvelope = (GM_Envelope) baseEnvelope1.clone();
176: } catch (Exception e) {
177: err
178: .println("## Problemes en recuperant l'emprise des couches dans les metadonnees ##");
179: System.exit(0);
180: }
181:
182: out.println("envelope : " + baseEnvelope);
183: out.println("test path : " + path);
184:
185: }
186:
187: // ########################################################################################
188: private void initFiles(String[] outDirPathTab,
189: PrintStream[] dataOutTab) throws Exception {
190: out.indentRight();
191:
192: int numAlgos = algorithmsName.length;
193:
194: for (int i = 0; i < numAlgos; i++) {
195: String algoName = algorithmsName[i];
196: String outDirPath = outDirPathTab[i] = path + "/"
197: + algoName + "/";
198: File outDirFile = new File(outDirPath);
199: outDirFile.mkdirs();
200: PrintStream dataOut = dataOutTab[i] = new PrintStream(
201: new FileOutputStream(outDirPath + "test.dat"));
202:
203: dataOut.println("# vim:ts=10");
204: dataOut.println("# Les temps sont donnés en millisecondes");
205: dataOut.println();
206: String datLine;
207: datLine = "" + "factor\t" + "size\t";
208:
209: if (testJts)
210: datLine = datLine + "jts\t";
211: if (testOracle)
212: datLine = datLine + "oracle\t";
213: if (testGeos)
214: datLine = datLine + "geos\t";
215: if (testJts && testOracle)
216: datLine = datLine + "jts/oracle\t";
217: if (testGeos && testOracle)
218: datLine = datLine + "geos/oracle\t";
219:
220: dataOut.println(datLine);
221: dataOut.println();
222: }
223: out.indentLeft();
224: }
225:
226: // ########################################################################################
227: private void loadInputGeom(double factor) throws Exception {
228: out.indentRight();
229:
230: long time;
231: time = time();
232:
233: GM_Envelope baseEnvelope = (GM_Envelope) this .baseEnvelope
234: .clone();
235: baseEnvelope.expandBy(factor);
236: GM_Polygon bbox = new GM_Polygon(baseEnvelope);
237:
238: FT_FeatureCollection featList1 = db.loadAllFeatures(featClass1,
239: bbox);
240: FT_FeatureCollection featList2 = db.loadAllFeatures(featClass2,
241: bbox);
242:
243: // creation des agregats
244: geom1.clear();
245: featList1.initIterator();
246: while (featList1.hasNext())
247: geom1.add(featList1.next().getGeom());
248: geom2.clear();
249: featList2.initIterator();
250: while (featList2.hasNext())
251: geom2.add(featList2.next().getGeom());
252:
253: out
254: .println("Creation: " + (time() - time) / 1000.
255: + " seconds");
256: out.println("Size of geom1: " + geom1.size());
257: out.println("Size of geom2: " + geom2.size());
258:
259: out.println("Envelope of geom1:");
260: out.indentRight();
261: out.println(geom1.envelope().toString());
262: out.indentLeft();
263:
264: out.println("Envelope of geom2:");
265: out.indentRight();
266: out.println(geom2.envelope().toString());
267: out.indentLeft();
268:
269: out.indentLeft();
270: }
271:
272: // ########################################################################################
273: private void saveImagesCm(int nbParameters, String outDirPath,
274: String factorString, int width, int height)
275: throws Exception {
276: out.indentRight();
277:
278: Color colorG1 = Color.GREEN;
279: Color colorG2 = Color.BLUE;
280: Color colorResult = Color.RED;
281: Color bg = Color.WHITE;
282:
283: GM_Object[] geomsJts;
284: GM_Object[] geomsOracle;
285: GM_Object[] geomsGeos;
286:
287: Color[] colors;
288: if (nbParameters == 1) {
289: geomsJts = new GM_Object[] { (GM_Object) resultJts, geom1 };
290: geomsOracle = new GM_Object[] { (GM_Object) resultOracle,
291: geom1 };
292: geomsGeos = new GM_Object[] { (GM_Object) resultGeos, geom1 };
293: colors = new Color[] { colorResult, colorG1 };
294: } else /*if (nbParameters==2) */{
295: geomsJts = new GM_Object[] { (GM_Object) resultJts, geom1,
296: geom2 };
297: geomsOracle = new GM_Object[] { (GM_Object) resultOracle,
298: geom1, geom2 };
299: geomsGeos = new GM_Object[] { (GM_Object) resultGeos,
300: geom1, geom2 };
301: colors = new Color[] { colorG1, colorG2, colorResult };
302: }
303:
304: if (testJts) {
305: String pfx1 = outDirPath + "jts_" + factorString;
306: String imgPath1 = pfx1 + ".png";
307: String svgzPath1 = pfx1 + ".svg.z";
308: out.println("Saving " + pfx1 + "...");
309: if (saveImage)
310: ImgUtil.saveImage(geomsJts, imgPath1, colors, bg,
311: width, height);
312: if (saveSvg)
313: ImgUtil.saveSvgz(geomsJts, svgzPath1, colors, bg,
314: width, height);
315: }
316:
317: if (testOracle) {
318: String pfx1 = outDirPath + "oracle_" + factorString;
319: String imgPath1 = pfx1 + ".png";
320: String svgzPath1 = pfx1 + ".svg.z";
321: out.println("Saving " + pfx1 + "...");
322: if (saveImage)
323: ImgUtil.saveImage(geomsOracle, imgPath1, colors, bg,
324: width, height);
325: if (saveSvg)
326: ImgUtil.saveSvgz(geomsOracle, svgzPath1, colors, bg,
327: width, height);
328: }
329:
330: if (testGeos) {
331: String pfx1 = outDirPath + "geos_" + factorString;
332: String imgPath1 = pfx1 + ".png";
333: String svgzPath1 = pfx1 + ".svg.z";
334: out.println("Saving " + pfx1 + "...");
335: if (saveImage)
336: ImgUtil.saveImage(geomsGeos, imgPath1, colors, bg,
337: width, height);
338: if (saveSvg)
339: ImgUtil.saveSvgz(geomsGeos, svgzPath1, colors, bg,
340: width, height);
341: }
342:
343: out.indentLeft();
344: }
345:
346: // ########################################################################################
347: private long launchJts(String realAlgoName, Class[] algoParamTypes,
348: Object[] algoParameters) throws Exception {
349: try {
350: out.indentRight();
351:
352: Class jtsAlgoClass = JtsAlgorithms.class;
353: Method jtsAlgo = jtsAlgoClass.getMethod(realAlgoName,
354: algoParamTypes);
355:
356: out.println("JTS...");
357: long time = time();
358: try {
359: resultJts = jtsAlgo.invoke(jts, algoParameters);
360: } catch (InvocationTargetException e) {
361: Throwable cause = e.getCause();
362: cause.printStackTrace();
363: if (cause instanceof TopologyException) {
364: CoordinateSequence jtsCoord = DefaultCoordinateSequenceFactory
365: .instance()
366: .create(
367: new Coordinate[] { ((TopologyException) cause)
368: .getCoordinate() });
369: DirectPosition geOxyCoord = JtsGeOxygene
370: .makeDirectPosition(jtsCoord);
371: resultJts = new GM_Point(geOxyCoord);
372: }
373: }
374: time = time() - time;
375: out.println("JTS: " + (time / 1000.) + " seconds");
376: long jtsTime = time;
377:
378: out.indentLeft();
379: return jtsTime;
380:
381: } catch (Exception e) {
382: e.printStackTrace();
383: return 10000000;
384: }
385: }
386:
387: // ########################################################################################
388: /* private long launchOracle(String realAlgoName, Class[] algoParamTypes, Object[] algoParameters)
389: {
390: try {
391: out.indentRight();
392:
393: Class oracleAlgoClass=OracleAlgorithms.class;
394: Method oracleAlgo=oracleAlgoClass.getMethod(realAlgoName,algoParamTypes);
395:
396: out.println("Oracle...");
397: long time=time();
398: resultOracle=oracleAlgo.invoke(oracle,algoParameters);
399: time=time()-time;
400: out.println("Oracle: "+(time/1000.)+" seconds");
401: long oracleTime=time;
402:
403: out.indentLeft();
404:
405: return oracleTime;
406:
407: } catch (Exception e) {
408: e.printStackTrace();
409: return 10000000;
410: }
411: }
412: */
413:
414: // ########################################################################################
415: private long launchGeos(String realAlgoName,
416: Class[] algoParamTypes, Object[] algoParameters)
417: throws Exception {
418: try {
419: out.indentRight();
420:
421: Class geosAlgoClass = GeosAlgorithms.class;
422: Method geosAlgo = geosAlgoClass.getMethod(realAlgoName,
423: algoParamTypes);
424:
425: out.println("Geos...");
426: long time = time();
427: resultGeos = geosAlgo.invoke(geos, algoParameters);
428: time = time() - time;
429: out.println("Geos: " + (time / 1000.) + " seconds");
430: long geosTime = time;
431:
432: out.indentLeft();
433:
434: return geosTime;
435:
436: } catch (Exception e) {
437: e.printStackTrace();
438: return 10000000;
439: }
440: }
441:
442: // ########################################################################################
443: private void launchAlgorithms(String[] outDirPathTab,
444: PrintStream[] dataOutTab, String factorString)
445: throws Exception {
446: out.indentRight();
447:
448: Class[] algoParamTypes = null;
449: Object[] algoParameters = null;
450: Class returnType = null;
451: Class geomAlgoClass = GeomAlgorithms.class;
452: Method[] geomAlgos = geomAlgoClass.getMethods();
453: int nbParameters = 0;
454:
455: for (int i = 0; i < algorithmsName.length; i++) {
456: PrintStream dataOut = dataOutTab[i];
457: String outDirPath = outDirPathTab[i];
458: String realAlgoName = algorithmsName[i];
459:
460: out.println(realAlgoName);
461:
462: /*-- ...Choix des parametres ---------------------------------*/
463: for (int j = 0; j < geomAlgos.length; j++) {
464: Method geomAlgo = geomAlgos[j];
465: if (geomAlgo.getName().equals(realAlgoName)) {
466: nbParameters = geomAlgo.getParameterTypes().length;
467: returnType = geomAlgo.getReturnType();
468: break;
469: }
470: }
471: if (nbParameters == 1) {
472: algoParamTypes = new Class[] { GM_Object.class };
473: algoParameters = new Object[] { geom1 };
474: } else if (nbParameters == 2) {
475: algoParamTypes = new Class[] { GM_Object.class,
476: GM_Object.class };
477: algoParameters = new Object[] { geom1, geom2 };
478: } else {
479: err
480: .println(" ## Probleme dans le choix des parametres ## ");
481: }
482:
483: /*-- ...Geos -------------------------------------------------*/
484: long geosTime = 0;
485: if (testGeos)
486: geosTime = launchGeos(realAlgoName, algoParamTypes,
487: algoParameters);
488:
489: /*-- ...Jts ----------------------------------------------------*/
490: long jtsTime = 0;
491: if (testJts)
492: jtsTime = launchJts(realAlgoName, algoParamTypes,
493: algoParameters);
494:
495: /*-- ...Oracle -------------------------------------------------*/
496: long oracleTime = 0;
497: // if (testOracle) oracleTime=launchOracle(realAlgoName,algoParamTypes,algoParameters);
498:
499: /*-- Print line in testresult file ---------------------------*/
500: String datLine;
501: datLine = "" + factorString + '\t' + geom1.size() + '\t';
502: if (nbParameters == 2)
503: datLine += geom2.size() + '\t';
504:
505: if (testJts)
506: datLine = datLine + jtsTime + '\t';
507: if (testOracle)
508: datLine = datLine + oracleTime + '\t';
509: if (testGeos)
510: datLine = datLine + geosTime + '\t';
511: if (testJts && testOracle)
512: datLine = datLine + ((double) jtsTime) / oracleTime
513: + '\t';
514: if (testGeos && testOracle)
515: datLine = datLine + ((double) geosTime) / oracleTime;
516:
517: dataOut.println(datLine);
518:
519: /*-- Make images ----------------------------------------*/
520: if (returnType == GM_Object.class) {
521: out.indentRight();
522: out.println("Saving images...");
523: int width = (int) baseEnvelope.width() / 100;
524: int height = (int) baseEnvelope.length() / 100;
525: saveImagesCm(nbParameters, outDirPath, factorString,
526: width, height);
527: out.indentLeft();
528: } else {
529: out.indentRight();
530: out.indentRight();
531: if (testJts)
532: out.println("result jts : " + resultJts);
533: if (testOracle)
534: out.println("result oracle : " + resultOracle);
535: if (testGeos)
536: out.println("result geos : " + resultGeos);
537: out.indentLeft();
538: out.indentLeft();
539: }
540: }
541:
542: out.indentLeft();
543: }
544:
545: // ########################################################################################
546: public void run() throws Exception {
547: out.indentRight();
548:
549: /*-- Create output directories and testresult files --------------*/
550: String[] outDirPathTab = new String[algorithmsName.length];
551: PrintStream[] dataOutTab = new PrintStream[outDirPathTab.length];
552: initFiles(outDirPathTab, dataOutTab);
553:
554: /* boucle reglant la taille des envelopes pour le chargement des objets */
555: for (double factor = min; factor <= max; factor += step) {
556: DecimalFormat format = new DecimalFormat();
557: format.setMaximumFractionDigits(2);
558: String factorString = format.format(factor);
559: out.println("Factor=" + factorString);
560:
561: /*-- Create input geometries ---------------------------------*/
562: out.println("Creating input geometries...");
563: loadInputGeom(factor);
564:
565: /*-- Launch algorithms ---------------------------------------*/
566: out.println("Launching algorithms...");
567: launchAlgorithms(outDirPathTab, dataOutTab, factorString);
568: }
569: out.indentLeft();
570: }
571:
572: // ########################################################################################
573: public static void main(String[] args) throws Exception {
574: CompareLib testApp = new CompareLib();
575: testApp.run();
576: }
577:
578: // ########################################################################################
579: private long time() {
580: return System.currentTimeMillis();
581: }
582:
583: // ########################################################################################
584: private class IndentedPrintStream extends PrintStream {
585: private String indent = "";
586:
587: public IndentedPrintStream(OutputStream out) {
588: super (out);
589: }
590:
591: public IndentedPrintStream(OutputStream out, boolean autoFlush) {
592: super (out, autoFlush);
593: }
594:
595: public IndentedPrintStream(OutputStream out, boolean autoFlush,
596: String encoding) throws UnsupportedEncodingException {
597: super (out, autoFlush, encoding);
598: }
599:
600: public void println(String x) {
601: StringTokenizer tkz = new StringTokenizer(x, "\n");
602: while (tkz.hasMoreTokens()) {
603: String line = tkz.nextToken();
604: super .print(indent);
605: super .println(line);
606: }
607: }
608:
609: public void indentRight() {
610: indent += "\t";
611: }
612:
613: public void indentLeft() {
614: indent = indent.replaceFirst("\t$", "");
615: }
616: }
617:
618: }
|