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 / service / ExportKMLService.java @ 950

History | View | Annotate | Download (17.9 KB)

1
/*
2
 * To change this license header, choose License Headers in Project Properties.
3
 * To change this template file, choose Tools | Templates
4
 * and open the template in the editor.
5
 */
6
package org.gvsig.gpe.exportto.kml.service;
7

    
8
import java.awt.geom.Rectangle2D;
9
import java.io.File;
10
import java.io.FileOutputStream;
11
import java.io.IOException;
12
import java.util.ArrayList;
13
import java.util.Iterator;
14
import java.util.List;
15
import java.util.Map;
16
import org.cresques.cts.ICoordTrans;
17
import org.cresques.cts.IProjection;
18
import org.gvsig.export.ExportException;
19
import org.gvsig.export.ExportParameters;
20
import org.gvsig.export.spi.AbstractExportService;
21
import org.gvsig.export.spi.ExportService;
22
import org.gvsig.export.spi.ExportServiceFactory;
23
import org.gvsig.fmap.crs.CRSFactory;
24
import org.gvsig.fmap.dal.DALLocator;
25
import org.gvsig.fmap.dal.DataManager;
26
import org.gvsig.fmap.dal.DataServerExplorer;
27
import org.gvsig.fmap.dal.NewDataStoreParameters;
28
import org.gvsig.fmap.dal.OpenDataStoreParameters;
29
import org.gvsig.fmap.dal.exception.DataException;
30
import org.gvsig.fmap.dal.feature.Feature;
31
import org.gvsig.fmap.dal.feature.FeatureAttributeDescriptor;
32
import org.gvsig.fmap.dal.feature.FeatureSet;
33
import org.gvsig.fmap.dal.feature.FeatureType;
34
import org.gvsig.fmap.dal.feature.NewFeatureStoreParameters;
35
import org.gvsig.fmap.dal.feature.OpenFeatureStoreParameters;
36
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
37
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
38
import org.gvsig.fmap.geom.DataTypes;
39
import org.gvsig.fmap.geom.Geometry;
40
import org.gvsig.fmap.geom.GeometryLocator;
41
import org.gvsig.fmap.geom.GeometryManager;
42
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
43
import org.gvsig.fmap.geom.primitive.Envelope;
44
import org.gvsig.fmap.mapcontext.MapContextException;
45
import org.gvsig.fmap.mapcontext.layers.vectorial.FLyrVect;
46
import org.gvsig.fmap.mapcontext.rendering.legend.IVectorLegend;
47
import org.gvsig.fmap.mapcontext.rendering.symbols.ISymbol;
48
import org.gvsig.gpe.exportto.generic.util.CoordinatesSequenceBbox;
49
import org.gvsig.gpe.exportto.generic.util.GeometryToGPEWriter;
50
import org.gvsig.gpe.exportto.kml.style.KmlStyle;
51
import org.gvsig.gpe.exportto.kml.style.StyleUtils;
52
import org.gvsig.gpe.lib.api.GPELocator;
53
import org.gvsig.gpe.lib.api.writer.IGPEWriterHandler;
54
import org.gvsig.gpe.lib.api.writer.IGPEWriterHandlerImplementor;
55
import org.gvsig.gpe.prov.kml.utils.Kml2_1_Tags;
56
import org.gvsig.gpe.prov.kml.writer.GPEKmlWriterHandlerImplementor;
57
import org.gvsig.tools.dispose.DisposableIterator;
58
import org.gvsig.tools.locator.LocatorException;
59
import org.gvsig.tools.util.HasAFile;
60
import org.gvsig.xmlpull.lib.api.stream.IXmlStreamWriter;
61
import org.slf4j.Logger;
62
import org.slf4j.LoggerFactory;
63

    
64
/**
65
 *
66
 * @author osc
67
 */
68
public class ExportKMLService extends AbstractExportService
69
        implements ExportService {
70

    
71
        private static Logger logger = LoggerFactory.getLogger(ExportKMLService.class);
72

    
73
        ExportKMLService(ExportServiceFactory factory, ExportParameters parameters) {
74
                super(factory, parameters);
75
        }
76

    
77
        @Override
78
        protected DataServerExplorer createServerExplorer() throws ExportException {
79

    
80
                DataManager dataManager = DALLocator.getDataManager();
81

    
82
                FilesystemServerExplorerParameters explorerParams;
83
                try {
84
                        explorerParams
85
                                = (FilesystemServerExplorerParameters) dataManager
86
                                        .createServerExplorerParameters(FilesystemServerExplorer.NAME);
87
                } catch (Exception e) {
88
                        throw new ExportException(e);
89
                }
90

    
91
                explorerParams.setRoot(this.getParameters().getFile().getParent());
92

    
93
                FilesystemServerExplorer explorer;
94
                try {
95
                        explorer = (FilesystemServerExplorer) dataManager.openServerExplorer(
96
                                "FilesystemExplorer", explorerParams
97
                        );
98
                        return explorer;
99
                } catch (Exception e) {
100
                        throw new ExportException(e);
101
                }
102
        }
103

    
104
        @Override
105
        protected NewDataStoreParameters createTargetNewStoreParameters() throws ExportException {
106
                try {
107
                        FilesystemServerExplorer explorer = (FilesystemServerExplorer) this.createServerExplorer();
108
                        NewFeatureStoreParameters newStoreParameters = (NewFeatureStoreParameters) explorer.getAddParameters(
109
                                this.getParameters().getFile()
110
                        );
111
                        newStoreParameters.setDynValue("CRS", this.getParameters().getTargetProjection());
112
                        // Usamos el featureType por defecto del KML
113
                        return newStoreParameters;
114
                } catch (DataException ex) {
115
                        throw new ExportException(ex);
116
                }
117
        }
118

    
119
        @Override
120
        protected OpenDataStoreParameters createTargetOpenStoreParameters() throws ExportException {
121
                try {
122
                        DataManager dataManager = DALLocator.getDataManager();
123
                        OpenFeatureStoreParameters openStoreParameters = (OpenFeatureStoreParameters) dataManager.createStoreParameters("GPE");
124
                        ((HasAFile) openStoreParameters).setFile(getParameters().getFile());
125
                        openStoreParameters.setDynValue("CRS", this.getParameters().getTargetProjection());
126
                        return openStoreParameters;
127
                } catch (DataException ex) {
128
                        throw new ExportException(ex);
129
                }
130
        }
131

    
132
        @Override
133
        public ExportKMLParameters getParameters() {
134
                return (ExportKMLParameters) super.getParameters();
135
        }
136

    
137
        @Override
138
        public void export(
139
                FeatureSet featureSet) throws ExportException {
140
                DataServerExplorer explorer = this.createServerExplorer();
141
                NewFeatureStoreParameters params = (NewFeatureStoreParameters) this.createTargetNewStoreParameters();
142

    
143
                String providerName = params.getDataStoreName();
144
                String explorerName = explorer.getProviderName();
145

    
146
                File outFile = this.getParameters().getFile(); //kmlFile;
147
                FeatureSet featureStore = featureSet;
148

    
149
                FLyrVect vectorLayer = null;
150
                String mimeType = this.getParameters().getMimeType(); //mtype;
151
                boolean useLabels = this.getParameters().getUseLabels(); //doLabels;
152
                boolean attsAsBalloon = this.getParameters().getAttsAsBalloon();
153
                ArrayList<ICoordTrans> ICoordTrans;
154

    
155
                List<ICoordTrans> transfList = new ArrayList<ICoordTrans>();
156

    
157
                ICoordTrans ct = this.getParameters().getSourceTransformation(); //vlayer.getCoordTrans();
158
                IProjection targetproj = this.getParameters().getTargetProjection();
159
//        if (reprojectTo4326) {
160
//                8
161
//            targetproj = CRSFactory.getCRS("EPSG:4326");
162
//            if (ct == null) {
163
//                transfList.add(this.getParameters().getSourceProjection().getCT(targetproj));
164
//            } else {
165
//                transfList.add(ct);
166
//                transfList.add(ct.getPDest().getCT(targetproj));
167
//            }
168
//        } else {
169
                if (ct == null) {
170
                        if (targetproj == null) {
171
                                targetproj = this.getParameters().getSourceProjection();
172
                        }
173
                        ct = this.getParameters().getSourceProjection().getCT(targetproj);
174
                        transfList.add(ct);
175
                } else {
176
                        targetproj = ct.getPDest();
177
                        transfList.add(ct);
178
                }
179

    
180
                IGPEWriterHandler wh = null;
181
                FileOutputStream fos = null;
182
                String srs = targetproj.getAbrev();
183

    
184
                String[] fldNames = null;
185
                Envelope env = null;
186
                long count = 0;
187
                FeatureType ftype;
188

    
189
                try {
190
                        count = featureSet.getSize();
191
                        this.getTaskStatus().setRangeOfValues(0, count);
192
                        if (this.getParameters().getExportAttributes().isActive()) {
193
                                ftype = this.getParameters().getExportAttributes().getTargetFeatureType();
194
                        } else {
195
                                ftype = featureStore.getDefaultFeatureType();
196
                        }
197
                        fldNames = getAttributes(ftype);
198
                        env = GeometryLocator.getGeometryManager().createEnvelope(Geometry.SUBTYPES.GEOM2D);
199
                        this.initEnvelope(env, featureSet);
200
                } catch (DataException | CreateEnvelopeException | LocatorException e) {
201
                        throw new ExportException(e);
202
                }
203

    
204
                try {
205
                        env = reproject(env, transfList);
206
                } catch (CreateEnvelopeException ex) {
207
                        throw new ExportException(ex);
208
                }
209

    
210
                Rectangle2D rect = new Rectangle2D.Double(
211
                        env.getMinimum(0),
212
                        env.getMinimum(1),
213
                        env.getLength(0),
214
                        env.getLength(1));
215

    
216
                File fixedFile = outFile;
217
                try {
218

    
219
                        if (!outFile.getAbsolutePath().toLowerCase().endsWith(
220
                                "." + this.getFileExtension().toLowerCase())) {
221

    
222
                                fixedFile = new File(outFile.getAbsolutePath() + "." + getFileExtension());
223
                        }
224

    
225
                        wh = GPELocator.getGPEManager().createWriterByMimeType(mimeType);
226
                        fos = new FileOutputStream(fixedFile);
227

    
228
                        wh.setOutputStream(fos);
229
                        wh.initialize();
230
                        // ==========================================
231
                        wh.startLayer(null, null, fixedFile.getName(), null, srs);
232
                        // ==============     Styles    =============
233
                        Map<ISymbol, KmlStyle> symsty = null;
234
                        IXmlStreamWriter xmlw = getXmlStreamWriter(wh);
235
                        if (true && xmlw != null && vectorLayer instanceof FLyrVect) {
236
                                symsty = StyleUtils.getSymbolStyles((FLyrVect) vectorLayer,
237
                                        featureSet,
238
                                        attsAsBalloon,
239
                                        fldNames);
240
                                Iterator<KmlStyle> iter = symsty.values().iterator();
241
                                KmlStyle sty = null;
242
                                while (iter.hasNext()) {
243
                                        sty = iter.next();
244
                                        writeStyle(xmlw, sty);
245
                                }
246
                        }
247
                        // ==========================================
248
                        wh.startBbox(null, new CoordinatesSequenceBbox(rect), srs);
249
                        wh.endBbox();
250
                        // ============= Writing feature ============
251
                        IVectorLegend legend;
252
                        if (vectorLayer instanceof FLyrVect) {
253
                                legend = (IVectorLegend) ((FLyrVect) vectorLayer).getLegend();
254
                        } else {
255
                                legend = null;
256
                        }
257
                        writeFeatures(wh, xmlw, featureSet, fldNames, symsty, legend, transfList);
258

    
259
//            writeFeatures(wh, xmlw, featureSet, fldNames, symsty,
260
//                    (IVectorLegend) vectorLayer.getLegend());
261
                        // ==========================================
262
                        wh.endLayer();
263
                        // ==========================================
264
                        wh.close();
265
                        fos.close();
266
                } catch (Exception exc) {
267
                        throw new ExportException(exc);
268
                }
269

    
270
                this.getTaskStatus().setCurValue(count);
271
//        this.finishAction(fixedFile, targetproj);
272
                this.getTaskStatus().terminate();
273
                this.getTaskStatus().remove();
274

    
275
        }
276

    
277
        private String[] getAttributes(FeatureType ftype) {
278

    
279
                FeatureAttributeDescriptor[] atts = ftype.getAttributeDescriptors();
280

    
281
                FeatureAttributeDescriptor desc = null;
282
                List<String> list = new ArrayList<String>();
283
                for (int i = 0; i < atts.length; i++) {
284
                        desc = atts[i];
285
                        if (desc.getDataType().getType() != DataTypes.GEOMETRY) {
286
                                list.add(desc.getName());
287
                        }
288
                }
289
                return list.toArray(new String[0]);
290
        }
291

    
292
        private Geometry reproject(Geometry geom, List<ICoordTrans> transfList) {
293

    
294
                int sz = transfList.size();
295
                if (sz == 0) {
296
                        return geom;
297
                } else {
298
                        Geometry resp = geom.cloneGeometry();
299
                        for (int i = 0; i < sz; i++) {
300
                                resp.reProject(transfList.get(i));
301
                        }
302
                        return resp;
303
                }
304

    
305
        }
306

    
307
        public String getFileExtension() {
308
                return "kml";
309
        }
310

    
311
//    private void finishAction(File kmlfile, IProjection proj)
312
//            throws ExportException {
313
//        
314
//        this.createTargetOpenStoreParameters()
315
//
316
//        if (exporttoServiceFinishAction != null) {
317
//
318
//            /*
319
//             * Export is done. We notify with a SHPStoreParameters,
320
//             * not with the NewSHPParameters we have used:
321
//             */
322
//            DataManagerProviderServices dataman
323
//                    = (DataManagerProviderServices) DALLocator.getDataManager();
324
//
325
//            DataStoreParameters dsp = null;
326
//            try {
327
//                dsp = dataman.createStoreParameters("GPE");
328
//            } catch (Exception e) {
329
//                throw new ExportException(e); //"Cannot add resulting kml file to view", e);
330
//            }
331
//
332
//            dsp.setDynValue("File", kmlfile);
333
//            dsp.setDynValue("CRS", proj);
334
//
335
//            try {
336
//                dsp.validate();
337
//            } catch (ValidateDataParametersException e) {
338
//                throw new ExportException(e);
339
//            }
340
//            exporttoServiceFinishAction.finished(kmlfile.getName(), dsp);
341
//        }
342
//    }
343
        private void writeStyle(IXmlStreamWriter xmlw, KmlStyle sty) throws IOException {
344

    
345
                xmlw.writeStartElement(Kml2_1_Tags.STYLE);
346
                xmlw.writeStartAttribute(Kml2_1_Tags.ID);
347
                xmlw.writeValue(sty.getId());
348
                xmlw.writeEndAttributes();
349
                sty.writeXml(xmlw);
350
                xmlw.writeEndElement();
351
        }
352

    
353
        private IXmlStreamWriter getXmlStreamWriter(IGPEWriterHandler wh) {
354

    
355
                IGPEWriterHandlerImplementor imple = wh.getImplementor();
356
                if (!(imple instanceof GPEKmlWriterHandlerImplementor)) {
357
                        /*
358
             * Unexpected class
359
                         */
360
                        return null;
361
                }
362
                GPEKmlWriterHandlerImplementor kmlimple = null;
363
                kmlimple = (GPEKmlWriterHandlerImplementor) imple;
364
                IXmlStreamWriter xmlw = kmlimple.getXMLStreamWriter();
365
                return xmlw;
366
        }
367

    
368
        private void writeFeatures(
369
                IGPEWriterHandler gwh,
370
                IXmlStreamWriter xmlw,
371
                FeatureSet fset,
372
                String[] fieldNames,
373
                Map<ISymbol, KmlStyle> symsty,
374
                IVectorLegend lege,
375
                List<ICoordTrans> transfList) throws Exception {
376

    
377
                GeometryToGPEWriter gw = new GeometryToGPEWriter(gwh);
378
                DisposableIterator diter = fset.fastIterator();
379
                Feature feat = null;
380
                long count = 0;
381
                this.getTaskStatus().setCurValue(count);
382
                ISymbol sym = null;
383
                int nullGeometries = 0;
384
                while (diter.hasNext()) {
385
                        feat = (Feature) diter.next();
386
                        try {
387
                                if (lege instanceof IVectorLegend) {
388
                                        sym = lege.getSymbolByFeature(feat);
389
                                }
390
                        } catch (MapContextException mce) {
391
                                logger.info("While getting legend symbol.", mce);
392
                        }
393
                        KmlStyle kmlStyle;
394
                        try {
395
                                kmlStyle = symsty.get(sym);
396
                        } catch (Exception e) {
397
                                kmlStyle = null;
398
                        }
399

    
400
                        if (!writeFeature(feat, gwh, xmlw, gw, count, fieldNames, kmlStyle, transfList)) {
401
                                nullGeometries++;
402
                        };
403
                        count++;
404
                        this.getTaskStatus().setCurValue(count);
405
                }
406
                if (nullGeometries > 0) {
407
                        logger.warn("Can't export " + nullGeometries + " features because source geometries are null.");
408
                }
409
                diter.dispose();
410
        }
411

    
412
        private boolean writeFeature(
413
                Feature feat,
414
                IGPEWriterHandler gwh,
415
                IXmlStreamWriter xmlw,
416
                GeometryToGPEWriter gw,
417
                long index,
418
                String[] fieldNames,
419
                KmlStyle ksty,
420
                List<ICoordTrans> transfList) throws IOException {
421

    
422
                Geometry geom = feat.getDefaultGeometry();
423

    
424
                if (geom == null) {
425
                        return false;
426
                }
427

    
428
                String strindex = String.valueOf(index);
429

    
430
                if (this.getParameters().getUseLabels()) {
431
                        String lbl = getLabelForFeature(feat);
432
                        gwh.startFeature(strindex, "FEATURE", lbl);
433
                } else {
434
                        gwh.startFeature(strindex, "FEATURE", "");
435
                }
436
                // =========================
437
                // Style
438
                if (ksty != null) {
439
                        xmlw.writeStartElement(Kml2_1_Tags.STYLEURL);
440
                        xmlw.writeValue("#" + ksty.getId());
441
                        xmlw.writeEndElement();
442
                }
443
                // ===== Balloon ============
444
                if (this.getParameters().getAttsAsBalloon()) {
445
                        writeBalloon(xmlw, feat, fieldNames);
446
                }
447

    
448
                // ============= Geometry
449

    
450
                /*
451
         * This has no effect if reprojection is not necessary
452
                 */
453
                geom = reproject(geom, transfList);
454
                gw.writeGeometry(geom, this.getParameters().getUseLabels());
455
                // ============= Attributes
456
                Object val = null;
457
                String fldname = null;
458
                for (int i = 0; i < fieldNames.length; i++) {
459
                        val = feat.get(fieldNames[i]);
460
                        fldname = fieldNames[i].replace(' ', '_');
461
                        gwh.startElement("", fldname, val == null ? "" : val.toString());
462
                        gwh.endElement();
463
                }
464
                // =========================
465
                gwh.endFeature();
466
                return true;
467
        }
468

    
469
        private String getLabelForFeature(Feature feat) {
470
                return "";
471

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

    
499
        private void writeBalloon(IXmlStreamWriter xmlw, Feature feat, String[] fieldNames)
500
                throws IOException {
501

    
502
                xmlw.writeStartElement(Kml2_1_Tags.EXTENDED_DATA);
503
                String fldrep = null;
504
                Object val = null;
505
                for (int i = 0; i < fieldNames.length; i++) {
506
                        fldrep = fieldNames[i].replace(' ', '_');
507
                        xmlw.writeStartElement(Kml2_1_Tags.DATA);
508
                        // Att =====================================================
509
                        xmlw.writeStartAttribute(null, "name");
510
                        xmlw.writeValue(fldrep);
511
                        xmlw.writeEndAttributes();
512
                        // Value =====================================================
513
                        xmlw.writeStartElement(Kml2_1_Tags.VALUE);
514
                        val = feat.get(fieldNames[i]);
515
                        xmlw.writeValue(val == null ? "" : val.toString());
516
                        xmlw.writeEndElement();
517
                        // =============================================
518
                        xmlw.writeEndElement();
519
                }
520
                xmlw.writeEndElement();
521

    
522
                /*
523
         *
524
<ExtendedData>
525
      <Data name="holeNumber">
526
        <value>1</value>
527
      </Data>
528
      <Data name="holeYardage">
529
        <value>234</value>
530
      </Data>
531
      <Data name="holePar">
532
        <value>4</value>
533
      </Data>
534
    </ExtendedData>
535
         *
536
                 */
537
        }
538

    
539
        private Envelope reproject(Envelope env, List<ICoordTrans> transfList) throws CreateEnvelopeException {
540

    
541
                int sz = transfList.size();
542
                if (sz == 0) {
543
                        return env;
544
                } else {
545
                        Envelope resp = env;
546
                        try {
547
                                for (int i = 0; i < sz; i++) {
548
                                        resp = resp.convert(transfList.get(i));
549
                                }
550
                        } catch (Exception exc) {
551

    
552
                                // If this process fails, we'll use "emergency values":
553
                                GeometryManager gm = GeometryLocator.getGeometryManager();
554
                                double[] min = new double[2];
555
                                double[] max = new double[2];
556
                                IProjection targetproj = this.getParameters().getTargetProjection();
557
                                if (targetproj.isProjected()) {
558
                                        min = new double[]{-20000000, -20000000};
559
                                        max = new double[]{20000000, 20000000};
560
                                } else {
561
                                        min = new double[]{-180, -90};
562
                                        max = new double[]{180, 90};
563
                                }
564

    
565
                                resp = gm.createEnvelope(
566
                                        min[0], min[1],
567
                                        max[0], max[1],
568
                                        Geometry.SUBTYPES.GEOM2D);
569

    
570
                        }
571
                        return resp;
572
                }
573
        }
574

    
575
        private void initEnvelope(Envelope env, FeatureSet featureSet) {
576
                for (Feature feature : featureSet) {
577
                        Geometry geometry = feature.getDefaultGeometry();
578
                        if (geometry != null && geometry.isValid()) {
579
                                env.add(geometry);
580
                        }
581
                }
582
        }
583
}