Statistics
| Revision:

root / org.gvsig.gpe / library / trunk / org.gvsig.gpe / org.gvsig.gpe.exportto / org.gvsig.gpe.exportto.kml / src / main / java / org / gvsig / gpe / exportto / kml / ExporttoKMLService.java @ 386

History | View | Annotate | Download (17.7 KB)

1
/**
2
 * gvSIG. Desktop Geographic Information System.
3
 *
4
 * Copyright (C) 2007-2013 gvSIG Association.
5
 *
6
 * This program is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU General Public License
8
 * as published by the Free Software Foundation; either version 3
9
 * of the License, or (at your option) any later version.
10
 *
11
 * This program is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 * GNU General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU General Public License
17
 * along with this program; if not, write to the Free Software
18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19
 * MA  02110-1301, USA.
20
 *
21
 * For any additional information, do not hesitate to contact us
22
 * at info AT gvsig.com, or visit our website www.gvsig.com.
23
 */
24
package org.gvsig.gpe.exportto.kml;
25

    
26
import java.awt.geom.Rectangle2D;
27
import java.io.File;
28
import java.io.FileOutputStream;
29
import java.io.IOException;
30
import java.util.ArrayList;
31
import java.util.Iterator;
32
import java.util.List;
33
import java.util.Map;
34

    
35
import org.cresques.cts.ICoordTrans;
36
import org.cresques.cts.IProjection;
37
import org.slf4j.Logger;
38
import org.slf4j.LoggerFactory;
39

    
40
import org.gvsig.exportto.ExporttoService;
41
import org.gvsig.exportto.ExporttoServiceException;
42
import org.gvsig.exportto.ExporttoServiceFinishAction;
43
import org.gvsig.exportto.swing.prov.file.AbstractExporttoFileService;
44
import org.gvsig.fmap.crs.CRSFactory;
45
import org.gvsig.fmap.dal.DALLocator;
46
import org.gvsig.fmap.dal.DataStoreParameters;
47
import org.gvsig.fmap.dal.exception.DataException;
48
import org.gvsig.fmap.dal.exception.InitializeException;
49
import org.gvsig.fmap.dal.exception.ProviderNotRegisteredException;
50
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
51
import org.gvsig.fmap.dal.feature.Feature;
52
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
53
import org.gvsig.fmap.dal.feature.FeatureSet;
54
import org.gvsig.fmap.dal.feature.FeatureStore;
55
import org.gvsig.fmap.dal.feature.FeatureType;
56
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
57
import org.gvsig.fmap.dal.spi.DataManagerProviderServices;
58
import org.gvsig.fmap.geom.DataTypes;
59
import org.gvsig.fmap.geom.Geometry;
60
import org.gvsig.fmap.geom.GeometryLocator;
61
import org.gvsig.fmap.geom.GeometryManager;
62
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
63
import org.gvsig.fmap.geom.primitive.Envelope;
64
import org.gvsig.fmap.mapcontext.MapContextException;
65
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
66
import org.gvsig.fmap.mapcontext.rendering.legend.ILegend;
67
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend;
68
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
69
import org.gvsig.gpe.exportto.generic.util.CoordinatesSequenceBbox;
70
import org.gvsig.gpe.exportto.generic.util.GeometryToGPEWriter;
71
import org.gvsig.gpe.exportto.kml.style.KmlStyle;
72
import org.gvsig.gpe.exportto.kml.style.StyleUtils;
73
import org.gvsig.gpe.lib.api.GPELocator;
74
import org.gvsig.gpe.lib.api.writer.IGPEWriterHandler;
75
import org.gvsig.gpe.lib.api.writer.IGPEWriterHandlerImplementor;
76
import org.gvsig.gpe.prov.kml.utils.Kml2_1_Tags;
77
import org.gvsig.gpe.prov.kml.writer.GPEKmlWriterHandlerImplementor;
78
import org.gvsig.tools.dispose.DisposableIterator;
79
import org.gvsig.tools.task.AbstractMonitorableTask;
80
import org.gvsig.tools.task.SimpleTaskStatus;
81
import org.gvsig.xmlpull.lib.api.stream.IXmlStreamWriter;
82

    
83
/**
84
 * @author gvSIG Team
85
 * @version $Id$
86
 * 
87
 */
88
public class ExporttoKMLService extends AbstractMonitorableTask implements
89
    ExporttoService {
90
    
91
    private static Logger logger = LoggerFactory.getLogger(ExporttoKMLService.class);
92

    
93
    private FeatureStore featureStore = null;
94
    private FLyrVect vectorLayer = null;
95
    private List<ICoordTrans> transfList = new ArrayList<ICoordTrans>();
96
    
97
    private String mimeType = null;
98
    private File outFile = null;
99
    
100
    private boolean useLabels = false;
101
    private boolean attsAsBalloon = false;
102
    private boolean reprojectTo4326 = false;
103
    
104
    private IProjection targetproj = null;
105
    
106

    
107
    private NewFeatureStoreParameters newFeatureStoreParameters;
108
    private ExporttoServiceFinishAction exporttoServiceFinishAction;
109

    
110

    
111
    public ExporttoKMLService(
112
        File kmlFile,
113
        FeatureStore fstore,
114
        FLyrVect vlayer,
115
        String mtype,
116
        
117
        boolean doLabels,
118
        boolean balloon,
119
        boolean reproject4326) {
120
            
121
        super("Export to KML");
122
        outFile = kmlFile;
123
        featureStore = fstore;
124
        vectorLayer = vlayer;
125
        mimeType = mtype;
126
        
127
        useLabels = doLabels;
128
        attsAsBalloon = balloon;
129
        reprojectTo4326 = reproject4326;
130
        
131
        ICoordTrans ct = vlayer.getCoordTrans(); 
132
        if (reprojectTo4326) {
133
            targetproj = CRSFactory.getCRS("EPSG:4326");
134
            if (ct == null) {
135
                transfList.add(vlayer.getProjection().getCT(targetproj));
136
            } else {
137
                transfList.add(ct);
138
                transfList.add(ct.getPDest().getCT(targetproj));
139
            }
140
        } else {
141
            if (ct == null) {
142
                targetproj = vectorLayer.getProjection();
143
            } else {
144
                targetproj = ct.getPDest();
145
                transfList.add(ct);
146
            }
147
        }
148
    }
149

    
150
    public NewFeatureStoreParameters getNewFeatureStoreParameters() {
151
        return newFeatureStoreParameters;
152
    }
153

    
154
    public void addParameters(
155
        NewFeatureStoreParameters newFeatureStoreParameters) {
156
        
157
        newFeatureStoreParameters.setDynValue("CRS", targetproj);
158
    }
159

    
160
    public String getFileExtension() {
161
        return "kml";
162
    }
163
    
164
    public void export(FeatureSet featureSet) throws ExporttoServiceException {
165
        
166
        IGPEWriterHandler wh = null;
167
        FileOutputStream fos = null;
168
        String srs = targetproj.getAbrev();
169
        
170
        String[] fldNames = null;
171
        Envelope env = null;
172
        long count = 0;
173
        
174
        try {
175
            count = featureSet.getSize();
176
            this.taskStatus.setRangeOfValues(0, count);
177
            fldNames = getAttributes(featureStore.getDefaultFeatureType());
178
            env = this.featureStore.getEnvelope();
179
        } catch (DataException e) {
180
            throw new ExporttoServiceException(e);
181
        }
182
        
183
        try {
184
            env = reproject(env);
185
        } catch (CreateEnvelopeException cee) {
186
            throw new ExporttoServiceException(cee);
187
        }
188
        
189
        Rectangle2D rect = new Rectangle2D.Double(
190
            env.getMinimum(0),
191
            env.getMinimum(1),
192
            env.getLength(0),
193
            env.getLength(1));
194
            
195
        File fixedFile = outFile;
196
        try {
197
            
198
            if (!outFile.getAbsolutePath().toLowerCase().endsWith(
199
                "." + this.getFileExtension().toLowerCase())) {
200
                
201
                fixedFile = new File(outFile.getAbsolutePath() + "." + getFileExtension());
202
            }
203
            
204
            wh = GPELocator.getGPEManager().createWriterByMimeType(mimeType);
205
            fos = new FileOutputStream(fixedFile);
206
            
207
            wh.setOutputStream(fos);
208
            wh.initialize();
209
            // ==========================================
210
            wh.startLayer(null, null, fixedFile.getName(), null, srs);
211
            // ==============     Styles    =============
212
            Map<ISymbol, KmlStyle> symsty = null;
213
            IXmlStreamWriter xmlw = getXmlStreamWriter(wh);
214
            if (true && xmlw != null) {
215
                symsty = StyleUtils.getSymbolStyles(
216
                    vectorLayer,
217
                    featureSet,
218
                    attsAsBalloon,
219
                    fldNames);
220
                Iterator<KmlStyle> iter = symsty.values().iterator();
221
                KmlStyle sty = null;
222
                while (iter.hasNext()) {
223
                    sty = iter.next();
224
                    writeStyle(xmlw, sty);
225
                }
226
            }
227
            // ==========================================
228
            wh.startBbox(null, new CoordinatesSequenceBbox(rect), srs);
229
            wh.endBbox();
230
            // ============= Writing feature ============
231
            writeFeatures(wh, xmlw, featureSet, fldNames, symsty,
232
                (IVectorLegend) vectorLayer.getLegend());
233
            // ==========================================
234
            wh.endLayer();
235
            // ==========================================
236
            wh.close();
237
            fos.close();
238
        } catch (Exception exc) {
239
            throw new ExporttoServiceException(exc);
240
        }
241
        
242
        this.taskStatus.setCurValue(count);
243
        this.taskStatus.terminate();
244
        this.finishAction(fixedFile, this.targetproj);
245
    }
246

    
247
    
248
    private Envelope reproject(Envelope env) throws CreateEnvelopeException {
249
        
250
        int sz = transfList.size(); 
251
        if (sz == 0) {
252
            return env;
253
        } else {
254
            Envelope resp = env;
255
            try {
256
                for (int i=0; i<sz; i++) {
257
                    resp = resp.convert(transfList.get(i));
258
                }
259
            } catch (Exception exc) {
260
                
261
                // If this process fails, we'll use "emergency values":
262
                GeometryManager gm = GeometryLocator.getGeometryManager();
263
                double[] min = new double[2];
264
                double[] max = new double[2];
265
                if (targetproj.isProjected()) {
266
                    min = new double[]{-20000000, -20000000};
267
                    max = new double[]{ 20000000,  20000000};
268
                } else {
269
                    min = new double[]{-180, -90};
270
                    max = new double[]{ 180,  90};
271
                }
272
                
273
                resp = gm.createEnvelope(
274
                    min[0], min[1],
275
                    max[0], max[1],
276
                    Geometry.SUBTYPES.GEOM2D);
277

    
278
            }
279
            return resp;
280
        }
281
    }
282

    
283
    private void writeStyle(IXmlStreamWriter xmlw, KmlStyle sty) throws IOException {
284
        
285
        xmlw.writeStartElement(Kml2_1_Tags.STYLE);
286
        xmlw.writeStartAttribute(Kml2_1_Tags.ID);
287
        xmlw.writeValue(sty.getId());           
288
        xmlw.writeEndAttributes();    
289
        sty.writeXml(xmlw);
290
        xmlw.writeEndElement();        
291
    }
292
    
293
    
294
    private IXmlStreamWriter getXmlStreamWriter(IGPEWriterHandler wh) {
295
        
296
        IGPEWriterHandlerImplementor imple = wh.getImplementor();
297
        if (!(imple instanceof GPEKmlWriterHandlerImplementor)) {
298
            /*
299
             * Unexpected class
300
             */
301
            return null;
302
        }
303
        GPEKmlWriterHandlerImplementor kmlimple = null;
304
        kmlimple = (GPEKmlWriterHandlerImplementor) imple;
305
        IXmlStreamWriter xmlw = kmlimple.getXMLStreamWriter();   
306
        return xmlw;
307
    }
308

    
309
    
310
    private void finishAction(File kmlfile, IProjection proj)
311
    throws ExporttoServiceException {
312

    
313
        if (exporttoServiceFinishAction != null) {
314
            
315
            /*
316
             * Export is done. We notify with a SHPStoreParameters,
317
             * not with the NewSHPParameters we have used:
318
             */
319
            DataManagerProviderServices dataman =
320
                (DataManagerProviderServices) DALLocator.getDataManager();
321
            
322
            DataStoreParameters dsp = null;
323
            try {
324
                dsp = dataman.createStoreParameters("GPE");
325
            } catch (Exception e) {
326
                throw new ExporttoServiceException(
327
                    "Cannot add resulting kml file to view", e);
328
            }
329
            
330
            dsp.setDynValue("File", kmlfile);
331
            dsp.setDynValue("CRS", proj);
332
            
333
            try {
334
                dsp.validate();
335
            } catch (ValidateDataParametersException e) {
336
                throw new ExporttoServiceException(e);
337
            }
338
            exporttoServiceFinishAction.finished(kmlfile.getName(), dsp);
339
        }
340
    }    
341
    
342
    private String[] getAttributes(FeatureType ftype) {
343
        
344
        FeatureAttributeDescriptor[] atts =  ftype.getAttributeDescriptors();
345
        FeatureAttributeDescriptor desc = null;
346
        List<String> list = new ArrayList<String>();
347
        for (int i=0; i<atts.length; i++) {
348
            desc = atts[i];
349
            if (desc.getDataType().getType() != DataTypes.GEOMETRY) {
350
                list.add(desc.getName());
351
            }
352
        }
353
        return list.toArray(new String[0]);
354
    }
355

    
356
    private void writeFeatures(
357
        IGPEWriterHandler gwh,
358
        IXmlStreamWriter xmlw,
359
        FeatureSet fset,
360
        String[] fieldNames,
361
        Map<ISymbol, KmlStyle> symsty,
362
        IVectorLegend lege) throws Exception {
363
        
364
        GeometryToGPEWriter gw = new GeometryToGPEWriter(gwh);
365
        DisposableIterator diter = fset.fastIterator();
366
        Feature feat = null;
367
        long count = 0;
368
        this.taskStatus.setCurValue(count);
369
        ISymbol sym = null;
370
        while (diter.hasNext()) {
371
            feat = (Feature) diter.next();
372
            try {
373
                sym = lege.getSymbolByFeature(feat);
374
            } catch (MapContextException mce) {
375
                logger.info("While getting legend symbol.", mce);
376
            }
377
            
378
            writeFeature(feat, gwh, xmlw, gw, count, fieldNames, symsty.get(sym));
379
            count++;
380
            this.taskStatus.setCurValue(count);
381
        }
382
        diter.dispose();
383
    }
384

    
385
    private void writeFeature(
386
        Feature feat,
387
        IGPEWriterHandler gwh,
388
        IXmlStreamWriter xmlw,
389
        GeometryToGPEWriter gw,
390
        long index,
391
        String[] fieldNames,
392
        KmlStyle ksty) throws IOException {
393
        
394
        String strindex = String.valueOf(index); 
395
        
396
        if (this.useLabels) {
397
            String lbl = getLabelForFeature(feat);
398
            gwh.startFeature(strindex, "FEATURE", lbl);
399
        } else {
400
            gwh.startFeature(strindex, "FEATURE", "");
401
        }
402
        // =========================
403
        // Style
404
        if (ksty != null) {
405
            xmlw.writeStartElement(Kml2_1_Tags.STYLEURL);
406
            xmlw.writeValue("#" + ksty.getId());           
407
            xmlw.writeEndElement();     
408
        }
409
        // ===== Balloon ============
410
        if (this.attsAsBalloon) {
411
            writeBalloon(xmlw, feat, fieldNames);
412
        }
413
        // ============= Geometry
414
        Geometry geom = feat.getDefaultGeometry();
415
        /*
416
         * This has no effect if reprojection is not necessary
417
         */
418
        geom = reproject(geom);
419
        gw.writeGeometry(geom, useLabels);
420
        // ============= Attributes
421
        Object val = null;
422
        String fldname = null;
423
        for (int i=0; i<fieldNames.length; i++) {
424
            val = feat.get(fieldNames[i]);
425
            fldname = fieldNames[i].replace(' ', '_');
426
            gwh.startElement("", fldname, val == null ? "" : val.toString());
427
            gwh.endElement();
428
        }
429
        // =========================
430
        gwh.endFeature();
431
    }
432
    
433
    private void writeBalloon(IXmlStreamWriter xmlw, Feature feat, String[] fieldNames)
434
    throws IOException {
435
        
436
        xmlw.writeStartElement(Kml2_1_Tags.EXTENDED_DATA);
437
        String fldrep = null;
438
        Object val = null;
439
        for (int i=0; i<fieldNames.length; i++) {
440
            fldrep = fieldNames[i].replace(' ', '_');
441
            xmlw.writeStartElement(Kml2_1_Tags.DATA);
442
            // Att =====================================================
443
            xmlw.writeStartAttribute(null, "name");
444
            xmlw.writeValue(fldrep);
445
            xmlw.writeEndAttributes();
446
            // Value =====================================================
447
            xmlw.writeStartElement(Kml2_1_Tags.VALUE);
448
            val = feat.get(fieldNames[i]);
449
            xmlw.writeValue(val == null ? "" : val.toString());
450
            xmlw.writeEndElement();
451
            // =============================================
452
            xmlw.writeEndElement();
453
        }
454
        xmlw.writeEndElement();
455
        
456
        /*
457
         *
458
<ExtendedData>
459
      <Data name="holeNumber">
460
        <value>1</value>
461
      </Data>
462
      <Data name="holeYardage">
463
        <value>234</value>
464
      </Data>
465
      <Data name="holePar">
466
        <value>4</value>
467
      </Data>
468
    </ExtendedData>
469
         * 
470
         */
471
        
472
    }
473

    
474
    private String getLabelForFeature(Feature feat) {
475
        
476
        if (this.vectorLayer.isLabeled()) {
477
            
478
            String[] flds = vectorLayer.getLabelingStrategy().getUsedFields();
479
            int n = Math.min(flds.length, 2);
480
            if (n == 0) {
481
                return "";
482
            } else {
483
                String resp = "";
484
                Object val = null; 
485
                if (n == 1) {
486
                    val = feat.get(flds[0]);
487
                    resp = (val == null) ? "" : val.toString();
488
                } else {
489
                    // n == 2
490
                    val = feat.get(flds[0]);
491
                    resp = (val == null) ? "" : val.toString();
492
                    val = feat.get(flds[1]);
493
                    resp = (val == null) ? resp : resp + ", " + val.toString();
494
                }
495
                return resp;
496
            }
497
            
498
        } else {
499
            return "";
500
        }
501
    }
502

    
503
    public void setFinishAction(
504
        ExporttoServiceFinishAction exporttoServiceFinishAction) {
505
        this.exporttoServiceFinishAction = exporttoServiceFinishAction;
506
    }
507
    
508
    private Geometry reproject(Geometry geom) {
509
        
510
        int sz = transfList.size(); 
511
        if (sz == 0) {
512
            return geom;
513
        } else {
514
            Geometry resp = geom.cloneGeometry();
515
            for (int i=0; i<sz; i++) {
516
                resp.reProject(transfList.get(i));
517
            }
518
            return resp;
519
        }
520
        
521
    }
522
    
523
}