Statistics
| Revision:

root / org.gvsig.dgn / trunk / org.gvsig.dgn / org.gvsig.dgn.provider / src / main / java / org / gvsig / fmap / dal / store / dgn / DGNStoreProvider.java @ 108

History | View | Annotate | Download (68.7 KB)

1
package org.gvsig.fmap.dal.store.dgn;
2

    
3
import java.awt.geom.AffineTransform;
4
import java.awt.geom.Arc2D;
5
import java.io.BufferedWriter;
6
import java.io.File;
7
import java.io.FileWriter;
8
import java.io.IOException;
9
import java.util.ArrayList;
10
import java.util.Date;
11
import java.util.HashMap;
12
import java.util.Iterator;
13
import java.util.List;
14
import java.util.Map;
15
import org.apache.commons.io.IOUtils;
16

    
17
import org.cresques.cts.IProjection;
18
import org.gvsig.fmap.dal.DALLocator;
19
import org.gvsig.fmap.dal.DataManager;
20
import org.gvsig.fmap.dal.DataServerExplorer;
21
import org.gvsig.fmap.dal.DataStoreNotification;
22
import org.gvsig.fmap.dal.DataTypes;
23
import org.gvsig.fmap.dal.FileHelper;
24
import org.gvsig.fmap.dal.exception.DataException;
25
import org.gvsig.fmap.dal.exception.InitializeException;
26
import org.gvsig.fmap.dal.exception.LoadException;
27
import org.gvsig.fmap.dal.exception.OpenException;
28
import org.gvsig.fmap.dal.exception.ReadException;
29
import org.gvsig.fmap.dal.exception.ValidateDataParametersException;
30
import org.gvsig.fmap.dal.feature.EditableFeatureAttributeDescriptor;
31
import org.gvsig.fmap.dal.feature.EditableFeatureType;
32
import org.gvsig.fmap.dal.feature.FeatureType;
33
import org.gvsig.fmap.dal.feature.exception.PerformEditingException;
34
import org.gvsig.fmap.dal.feature.spi.FeatureProvider;
35
import org.gvsig.fmap.dal.feature.spi.FeatureStoreProviderServices;
36
import org.gvsig.fmap.dal.feature.spi.memory.AbstractMemoryStoreProvider;
37
import org.gvsig.fmap.dal.resource.ResourceAction;
38
import org.gvsig.fmap.dal.resource.exception.AccessResourceException;
39
import org.gvsig.fmap.dal.resource.file.FileResource;
40
import org.gvsig.fmap.dal.resource.spi.ResourceConsumer;
41
import org.gvsig.fmap.dal.resource.spi.ResourceProvider;
42
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorer;
43
import org.gvsig.fmap.dal.serverexplorer.filesystem.FilesystemServerExplorerParameters;
44
import org.gvsig.fmap.dal.spi.DataStoreProviderServices;
45
import org.gvsig.fmap.dal.store.dgn.lib.DGNElemArc;
46
import org.gvsig.fmap.dal.store.dgn.lib.DGNElemComplexHeader;
47
import org.gvsig.fmap.dal.store.dgn.lib.DGNElemCore;
48
import org.gvsig.fmap.dal.store.dgn.lib.DGNElemMultiPoint;
49
import org.gvsig.fmap.dal.store.dgn.lib.DGNElemText;
50
import org.gvsig.fmap.dal.store.dgn.lib.DGNFileHeader;
51
import org.gvsig.fmap.dal.store.dgn.lib.DGNLink;
52
import org.gvsig.fmap.dal.store.dgn.lib.DGNPoint;
53
import org.gvsig.fmap.dal.store.dgn.lib.DGNReader;
54
import org.gvsig.fmap.geom.Geometry;
55
import org.gvsig.fmap.geom.GeometryLocator;
56
import org.gvsig.fmap.geom.GeometryManager;
57
import org.gvsig.fmap.geom.Geometry.SUBTYPES;
58
import org.gvsig.fmap.geom.Geometry.TYPES;
59
import org.gvsig.fmap.geom.exception.CreateEnvelopeException;
60
import org.gvsig.fmap.geom.exception.CreateGeometryException;
61
import org.gvsig.fmap.geom.primitive.Envelope;
62
import org.gvsig.fmap.geom.primitive.GeneralPathX;
63
import org.gvsig.fmap.geom.primitive.OrientablePrimitive;
64
import org.gvsig.fmap.geom.primitive.Point;
65
import org.gvsig.tools.dynobject.exception.DynMethodException;
66
import org.slf4j.Logger;
67
import org.slf4j.LoggerFactory;
68

    
69
public class DGNStoreProvider extends AbstractMemoryStoreProvider implements
70
        ResourceConsumer {
71

    
72
    private static final Logger logger = LoggerFactory.getLogger(DGNStoreProvider.class);
73

    
74
    public static final String NAME = "DGN";
75
    public static final String DESCRIPTION = "DGN file";
76

    
77
    public static final String METADATA_DEFINITION_NAME = NAME;
78
    public static final String METADATA_DEFINITION_DESCRIPTION = "DGN File Store";
79

    
80
    public static final int LOAD_MODE_PLAIN = 0;
81
    public static final int LOAD_MODE_GROUP1 = 1;
82

    
83
    public static final int CROP_OPERATION_NONE = 0;
84
    public static final int CROP_OPERATION_CONTAINS = 1;
85
    public static final int CROP_OPERATION_COVERS = 2;
86
    public static final int CROP_OPERATION_COVEREDBY = 3;
87
    public static final int CROP_OPERATION_CROSSES = 4;
88
    public static final int CROP_OPERATION_DISJOINT = 5;
89
    public static final int CROP_OPERATION_INTERSECT = 6;
90
    public static final int CROP_OPERATION_OVERLAPS = 7;
91
    public static final int CROP_OPERATION_TOUCHES = 8;
92
    public static final int CROP_OPERATION_WITHIN = 9;
93

    
94
    public static final int GROUP_GEOMETRIES_NONE = 0;
95
    public static final int GROUP_GEOMETRIES_CONVEXHULL = 1;
96
    public static final int GROUP_GEOMETRIES_UNION = 2;
97
    public static final int GROUP_GEOMETRIES_INTERSECTION = 3;
98
    public static final int GROUP_GEOMETRIES_TOPOINTS = 4;
99
    public static final int GROUP_GEOMETRIES_TOLINES = 5;
100
    public static final int GROUP_GEOMETRIES_TOPOLYGONS = 6;
101
    public static final int GROUP_GEOMETRIES_TOPOLYGONS_FIX = 7;
102

    
103
    public static final String NAME_FIELD_ID = "ID";
104
    public static final String NAME_FIELD_GEOMETRY = "Geometry";
105
    public static final String NAME_FIELD_TYPE = "Type";
106
    public static final String NAME_FIELD_STYPE = "SType";
107
    public static final String NAME_FIELD_ENTITY = "Entity";
108
    public static final String NAME_FIELD_LEVEL = "Layer";
109
    public static final String NAME_FIELD_COLOR = "Color";
110
    public static final String NAME_FIELD_FILLCOLOR = "FillColor";
111
    public static final String NAME_FIELD_ELEVATION = "Elevation";
112
    public static final String NAME_FIELD_WEIGHT = "Weight";
113
    public static final String NAME_FIELD_TEXT = "Text";
114
    public static final String NAME_FIELD_HEIGHTTEXT = "HeightText";
115
    public static final String NAME_FIELD_HEIGHTTEXTRAW = "HeightTextRaw";
116
    public static final String NAME_FIELD_ROTATIONTEXT = "Rotation";
117
    public static final String NAME_FIELD_STYLE = "Style";
118
    public static final String NAME_FIELD_GROUP = "Group";
119
    public static final String NAME_FIELD_ISSHAPE = "IsShape";
120
    public static final String NAME_FIELD_ISCOMPLEXSHAPEHEADER = "IsComplexShapeHeader";
121
    public static final String NAME_FIELD_ISHOLE = "IsHole";
122
    public static final String NAME_FIELD_ISCOMPLEX = "IsComplex";
123
    public static final String NAME_FIELD_PARENTID = "ParentId";
124
    public static final String NAME_FIELD_SCALE = "Scale";
125
    public static final String NAME_FIELD_LINKS_COUNT = "LinksCount";
126
    public static final String NAME_FIELD_LINK_INDEX = "LinkIndex";
127
    public static final String NAME_FIELD_LINK_TYPE = "LinkType";
128
    public static final String NAME_FIELD_LINK_ENTITY = "LinkEntity";
129
    public static final String NAME_FIELD_LINK_MS = "LinkMS";
130
    public static final String NAME_FIELD_LINK_LENGTH = "LinkLength";
131
    public static final String NAME_FIELD_LINK_DATA = "LinkData";
132
    public static final String NAME_FIELD_DATA = "Data";
133

    
134
    private int ID_FIELD_ID;
135
    private int ID_FIELD_TYPE;
136
    private int ID_FIELD_STYPE;
137
    private int ID_FIELD_ENTITY;
138
    private int ID_FIELD_LEVEL;
139
    private int ID_FIELD_COLOR;
140
    private int ID_FIELD_FILLCOLOR;
141
    private int ID_FIELD_ELEVATION;
142
    private int ID_FIELD_WEIGHT;
143
    private int ID_FIELD_TEXT;
144
    private int ID_FIELD_HEIGHTTEXT;
145
    private int ID_FIELD_HEIGHTTEXTRAW;
146
    private int ID_FIELD_ROTATIONTEXT;
147
    private int ID_FIELD_STYLE;
148
    private int ID_FIELD_GROUP;
149
    private int ID_FIELD_LAYER;
150
    private int ID_FIELD_ISCOMPLEXSHAPEHEADER;
151
    private int ID_FIELD_ISSHAPE;
152
    private int ID_FIELD_ISHOLE;
153
    private int ID_FIELD_ISCOMPLEX;
154
    private int ID_FIELD_PARENT;
155
    private int ID_FIELD_SCALE;
156
    private int ID_FIELD_LINKS_COUNT;
157
    private int ID_FIELD_LINK_INDEX;
158
    private int ID_FIELD_LINK_TYPE;
159
    private int ID_FIELD_LINK_ENTITY;
160
    private int ID_FIELD_LINK_MS;
161
    private int ID_FIELD_LINK_LENGTH;
162
    private int ID_FIELD_LINK_DATA;
163
    private int ID_FIELD_DATA;
164
    private int ID_FIELD_GEOMETRY;
165
    private int MAX_FIELD_ID;
166

    
167
    private IProjection projection;
168
    private ResourceProvider resource;
169
    private LegendBuilder legendBuilder;
170

    
171
    private long counterNewsOIDs = 0;
172
    protected GeometryManager geomManager = GeometryLocator.getGeometryManager();
173

    
174
    private int groupByFieldIndex = -2;
175
    private Map<Object, FeatureProvider> groupedFeatures = null;
176

    
177
    DGNData dgndata = null;
178

    
179
    public DGNStoreProvider(DGNStoreParameters parameters,
180
            DataStoreProviderServices storeServices) throws InitializeException {
181
        super(
182
                parameters,
183
                storeServices,
184
                FileHelper.newMetadataContainer(METADATA_DEFINITION_NAME)
185
        );
186

    
187
        counterNewsOIDs = 0;
188
        //                projection = CRSFactory.getCRS(getParameters().getSRSID());
189

    
190
        File file = getDGNParameters().getFile();
191
        resource = this.createResource(
192
                FileResource.NAME,
193
                new Object[]{file.getAbsolutePath()}
194
        );
195

    
196
        resource.addConsumer(this);
197

    
198
        this.projection = this.getDGNParameters().getCRS();
199

    
200
        try {
201
            legendBuilder = (LegendBuilder) this.invokeDynMethod(
202
                    LegendBuilder.DYNMETHOD_BUILDER_NAME, null);
203
        } catch (DynMethodException e) {
204
            legendBuilder = null;
205
        } catch (Exception e) {
206
            throw new InitializeException(e);
207
        }
208

    
209
        this.initializeFeatureTypes();
210

    
211
    }
212

    
213
    private DGNStoreParameters getDGNParameters() {
214
        return (DGNStoreParameters) this.getParameters();
215
    }
216

    
217
    public String getProviderName() {
218
        return NAME;
219
    }
220

    
221
    public boolean allowWrite() {
222
        // not yet
223
        return false;
224
    }
225

    
226
    public Object getLegend() throws OpenException {
227
        this.open();
228
        if (legendBuilder == null) {
229
            return null;
230
        }
231
        return legendBuilder.getLegend();
232
    }
233

    
234
    public Object getLabeling() throws OpenException {
235
        this.open();
236
        if (legendBuilder == null) {
237
            return null;
238
        }
239
        return legendBuilder.getLabeling();
240
    }
241

    
242
    private class DGNData {
243

    
244
        public List data = null;
245
        public FeatureType defaultFType = null;
246
        public List fTypes = null;
247
        public Envelope envelope = null;
248
        public IProjection projection;
249
        public LegendBuilder legendBuilder;
250

    
251
        public Envelope getEnvelopeCopy() throws CreateEnvelopeException {
252
            if (envelope == null) {
253
                return null;
254
            }
255
            try {
256
                return (Envelope) envelope.clone();
257
            } catch (CloneNotSupportedException ex) {
258
                logger.warn("Can't clone envelope.", ex);
259
                return null;
260
            }
261
        }
262
    }
263

    
264
    public static class TimeCounter {
265
        private static final Logger logger = LoggerFactory.getLogger(TimeCounter.class);
266
        
267
        private long counter = 0;
268
        private Date t1;
269
        private Date t2;
270
        
271
        public void start() {
272
            this.t1 = new Date();
273
            this.t2 = this.t1;
274
        }
275
        
276
        public void restart() {
277
            this.t1 = new Date();
278
            this.t2 = this.t1;
279
            this.counter = 0;
280
        }
281

    
282
        public void stop() {
283
            this.t2 = new Date();
284
            this.counter += this.t2.getTime()- this.t1.getTime();
285
        }
286
        public long get() {
287
            return this.counter;
288
        }
289
        public void log(String msg) {
290
            logger.debug("Time "+get()+" ms. " + msg);
291
        }
292
        public void restart(String msg) {
293
            this.stop();
294
            this.log(msg);
295
            this.restart();
296
        }
297
    }
298
    
299
    public void open() throws OpenException {
300
        if (this.data != null) {
301
            return;
302
        }
303
        try {
304
            getResource().execute(new ResourceAction() {
305
                public Object run() throws Exception {
306
                    
307
                    TimeCounter tc = new TimeCounter();
308
                    tc.start();
309
                    
310
                    FeatureStoreProviderServices store = getStoreServices();
311
                    if (dgndata == null
312
                            && !(getDGNParameters().useReload())) {
313
                        if (resource.getData() != null) {
314
                            dgndata = (DGNData) ((Map) resource.getData()).get(projection.getAbrev()); // OJO
315
                            // no es del todo correcto (puede llevar reproyeccion)
316
                        } else {
317
                            resource.setData(new HashMap());
318
                        }
319
                    }
320
                    tc.restart("Retrive data from resource (data="+dgndata+")");
321
                    
322
                    if (dgndata == null) {
323
                        dgndata = new DGNData();
324
                        dgndata.data = new ArrayList();
325
                        data = dgndata.data;
326
                        counterNewsOIDs = 0;
327
                        Reader reader = new Reader().initialice(
328
                                getMemoryProvider(),
329
                                (File) resource.get(),
330
                                projection, legendBuilder);
331
                        reader.begin(store);
332
                        dgndata.defaultFType = reader.getDefaultType().getNotEditableCopy();
333
                        List types = new ArrayList();
334
                        Iterator it = reader.getTypes().iterator();
335
                        EditableFeatureType fType;
336
                        while (it.hasNext()) {
337
                            fType = (EditableFeatureType) it.next();
338
                            if (fType.getId().equals(
339
                                    dgndata.defaultFType.getId())) {
340
                                types.add(dgndata.defaultFType);
341
                            } else {
342
                                types.add(fType.getNotEditableCopy());
343
                            }
344
                        }
345
                        dgndata.fTypes = types;
346

    
347
                        resource.notifyOpen();
348
                        store.setFeatureTypes(dgndata.fTypes,
349
                                dgndata.defaultFType);
350
                        reader.load();
351
                        dgndata.envelope = reader.getEnvelope();
352
                        dgndata.legendBuilder = legendBuilder;
353
                        dgndata.projection = projection;
354
                        reader.end();
355
                        if (resource.getData() == null) {
356
                            resource.setData(new HashMap());
357
                        }
358
                        ((Map) resource.getData()).put(
359
                                projection.getAbrev(),
360
                                dgndata); // OJO la reproyeccion
361
                        tc.restart("Loaded data from file (data="+dgndata+")");
362
                        resource.notifyClose();
363
                    }
364
                    // El feature type no lo compartimos entre las instancias del 
365
                    // mismo resource ya que puede cambiar en funcion del filtro.
366
                    // Por lo menos el geometry-type.
367
                    List<FeatureType> featureTypes = getFeatureTypes(store);
368

    
369
                    tc.restart("Created featuretype (featureTypes="+featureTypes+")");
370
                    
371
                    PostProcessFeatures postProcess = new PostProcessFeatures(
372
                            getDGNParameters(),
373
                            featureTypes.get(0)
374
                    );
375
                    if (postProcess.hasOperations()) {
376
                        data = postProcess.apply(dgndata.data);
377
                        setDynValue("Envelope", postProcess.getEnvelope());
378
                    } else {
379
                        data = dgndata.data;
380
                        setDynValue("Envelope", dgndata.getEnvelopeCopy());
381
                    }
382
                    tc.restart("PostProcessFeatures");
383

    
384
                    legendBuilder = dgndata.legendBuilder;
385
                    store.setFeatureTypes(featureTypes, featureTypes.get(0));
386
                    setDynValue("CRS", projection);
387
                    counterNewsOIDs = data.size();
388
                    tc.restart("load finished.");
389
                    return null;
390
                }
391
            });
392
        } catch (Exception e) {
393
            data = null;
394
            try {
395
                throw new OpenException(resource.getName(), e);
396
            } catch (AccessResourceException e1) {
397
                throw new OpenException(getProviderName(), e);
398
            }
399
        }
400
    }
401

    
402
    public DataServerExplorer getExplorer() throws ReadException {
403
        DataManager manager = DALLocator.getDataManager();
404
        FilesystemServerExplorerParameters params;
405
        try {
406
            params = (FilesystemServerExplorerParameters) manager
407
                    .createServerExplorerParameters(FilesystemServerExplorer.NAME);
408
            params.setRoot(this.getDGNParameters().getFile().getParent());
409
            return manager.openServerExplorer(FilesystemServerExplorer.NAME, params);
410
        } catch (DataException e) {
411
            throw new ReadException(this.getProviderName(), e);
412
        } catch (ValidateDataParametersException e) {
413
            throw new ReadException(this.getProviderName(), e);
414
        }
415

    
416
    }
417

    
418
    public void performChanges(Iterator deleteds, Iterator inserteds, Iterator updateds, Iterator originalFeatureTypesUpdated) throws PerformEditingException {
419
        // FIXME Exception
420
        throw new UnsupportedOperationException();
421
    }
422

    
423
    public List getFeatureTypes(FeatureStoreProviderServices store) {
424
        EditableFeatureType featureType = store.createFeatureType(getName());
425

    
426
        featureType.setHasOID(true);
427

    
428
        ID_FIELD_ID = featureType.add(NAME_FIELD_ID, DataTypes.INT)
429
                .setDefaultValue(Integer.valueOf(0))
430
                .getIndex();
431

    
432
        ID_FIELD_PARENT = featureType.add(NAME_FIELD_PARENTID, DataTypes.INT)
433
                .setDefaultValue(Integer.valueOf(0))
434
                .getIndex();
435

    
436
        // FIXME: Cual es el size y el valor por defecto para Entity ?
437
        ID_FIELD_ENTITY = featureType.add(NAME_FIELD_ENTITY, DataTypes.STRING, 100)
438
                .setDefaultValue("")
439
                .getIndex();
440

    
441
        // FIXME: Cual es el size de Layer ?
442
        ID_FIELD_LEVEL = featureType.add(NAME_FIELD_LEVEL, DataTypes.STRING, 100)
443
                .setDefaultValue("default")
444
                .getIndex();
445
        ID_FIELD_LAYER = ID_FIELD_LEVEL;
446

    
447
        ID_FIELD_COLOR = featureType.add(NAME_FIELD_COLOR, DataTypes.INT)
448
                .setDefaultValue(Integer.valueOf(0))
449
                .getIndex();
450

    
451
        // FIXME: Cual es el size de Text ?
452
        ID_FIELD_TEXT = featureType.add(NAME_FIELD_TEXT, DataTypes.STRING, 100)
453
                .setDefaultValue("")
454
                .getIndex();
455

    
456
        ID_FIELD_HEIGHTTEXT = featureType.add(NAME_FIELD_HEIGHTTEXT, DataTypes.DOUBLE)
457
                .setDefaultValue(Double.valueOf(10))
458
                .getIndex();
459

    
460
        ID_FIELD_HEIGHTTEXTRAW = featureType.add(NAME_FIELD_HEIGHTTEXTRAW, DataTypes.DOUBLE)
461
                .setDefaultValue(Double.valueOf(10))
462
                .getIndex();
463

    
464
        ID_FIELD_ROTATIONTEXT = featureType.add(NAME_FIELD_ROTATIONTEXT, DataTypes.DOUBLE)
465
                .setDefaultValue(Double.valueOf(0))
466
                .getIndex();
467

    
468
        ID_FIELD_TYPE = featureType.add(NAME_FIELD_TYPE, DataTypes.INT)
469
                .setDefaultValue(Integer.valueOf(0))
470
                .getIndex();
471

    
472
        ID_FIELD_STYPE = featureType.add(NAME_FIELD_STYPE, DataTypes.INT)
473
                .setDefaultValue(Integer.valueOf(0))
474
                .getIndex();
475

    
476
        ID_FIELD_FILLCOLOR = featureType.add(NAME_FIELD_FILLCOLOR, DataTypes.INT)
477
                .setDefaultValue(Integer.valueOf(0))
478
                .getIndex();
479

    
480
        ID_FIELD_STYLE = featureType.add(NAME_FIELD_STYLE, DataTypes.INT)
481
                .setDefaultValue(Integer.valueOf(0))
482
                .getIndex();
483

    
484
        ID_FIELD_ELEVATION = featureType.add(NAME_FIELD_ELEVATION, DataTypes.DOUBLE)
485
                .setDefaultValue(Double.valueOf(0))
486
                .getIndex();
487

    
488
        ID_FIELD_WEIGHT = featureType.add(NAME_FIELD_WEIGHT, DataTypes.DOUBLE)
489
                .setDefaultValue(Double.valueOf(0))
490
                .getIndex();
491

    
492
        ID_FIELD_GROUP = featureType.add(NAME_FIELD_GROUP, DataTypes.INT)
493
                .setDefaultValue(Integer.valueOf(0))
494
                .getIndex();
495

    
496
        ID_FIELD_ISSHAPE = featureType.add(NAME_FIELD_ISSHAPE, DataTypes.BOOLEAN)
497
                .setDefaultValue(Boolean.FALSE)
498
                .getIndex();
499

    
500
        ID_FIELD_ISCOMPLEXSHAPEHEADER = featureType.add(NAME_FIELD_ISCOMPLEXSHAPEHEADER, DataTypes.BOOLEAN)
501
                .setDefaultValue(Boolean.FALSE)
502
                .getIndex();
503

    
504
        ID_FIELD_ISHOLE = featureType.add(NAME_FIELD_ISHOLE, DataTypes.BOOLEAN)
505
                .setDefaultValue(Boolean.FALSE)
506
                .getIndex();
507

    
508
        ID_FIELD_ISCOMPLEX = featureType.add(NAME_FIELD_ISCOMPLEX, DataTypes.BOOLEAN)
509
                .setDefaultValue(Boolean.FALSE)
510
                .getIndex();
511

    
512
        ID_FIELD_SCALE = featureType.add(NAME_FIELD_SCALE, DataTypes.INT)
513
                .setDefaultValue(Integer.valueOf(0))
514
                .getIndex();
515

    
516
        ID_FIELD_LINKS_COUNT = featureType.add(NAME_FIELD_LINKS_COUNT, DataTypes.INT)
517
                .setDefaultValue(Integer.valueOf(0))
518
                .getIndex();
519

    
520
        ID_FIELD_LINK_INDEX = featureType.add(NAME_FIELD_LINK_INDEX, DataTypes.INT)
521
                .setDefaultValue(Integer.valueOf(0))
522
                .getIndex();
523

    
524
        ID_FIELD_LINK_ENTITY = featureType.add(NAME_FIELD_LINK_ENTITY, DataTypes.INT)
525
                .setDefaultValue(Integer.valueOf(0))
526
                .getIndex();
527

    
528
        ID_FIELD_LINK_TYPE = featureType.add(NAME_FIELD_LINK_TYPE, DataTypes.INT)
529
                .setDefaultValue(Integer.valueOf(0))
530
                .getIndex();
531

    
532
        ID_FIELD_LINK_MS = featureType.add(NAME_FIELD_LINK_MS, DataTypes.INT)
533
                .setDefaultValue(Integer.valueOf(0))
534
                .getIndex();
535

    
536
        ID_FIELD_LINK_LENGTH = featureType.add(NAME_FIELD_LINK_LENGTH, DataTypes.INT)
537
                .setDefaultValue(Integer.valueOf(0))
538
                .getIndex();
539

    
540
        ID_FIELD_LINK_DATA = featureType.add(NAME_FIELD_LINK_DATA, DataTypes.STRING, 512)
541
                .setDefaultValue("")
542
                .getIndex();
543

    
544
        ID_FIELD_DATA = featureType.add(NAME_FIELD_DATA, DataTypes.STRING, 512)
545
                .setDefaultValue("")
546
                .getIndex();
547

    
548
        EditableFeatureAttributeDescriptor attr = featureType.add(NAME_FIELD_GEOMETRY, DataTypes.GEOMETRY);
549
        attr.setSRS(this.projection);
550
        int geometryTypeToUse = getDGNParameters().getGeometryTypeFilter();
551
        if (getDGNParameters().getGroupBy() != null) {
552
            switch (getDGNParameters().getGroupGeometriesOperation()) {
553
                case GROUP_GEOMETRIES_NONE:
554
                case GROUP_GEOMETRIES_UNION:
555
                case GROUP_GEOMETRIES_INTERSECTION:
556
                    break;
557
                case GROUP_GEOMETRIES_TOPOINTS:
558
                    geometryTypeToUse = Geometry.TYPES.MULTIPOINT;
559
                    break;
560
                case GROUP_GEOMETRIES_TOLINES:
561
                    geometryTypeToUse = Geometry.TYPES.MULTICURVE;
562
                    break;
563
                case GROUP_GEOMETRIES_TOPOLYGONS:
564
                case GROUP_GEOMETRIES_TOPOLYGONS_FIX:
565
                case GROUP_GEOMETRIES_CONVEXHULL:
566
                    geometryTypeToUse = Geometry.TYPES.MULTISURFACE;
567
                    break;
568
            }
569
        }
570
        attr.setGeometryType(geometryTypeToUse);
571
        attr.setGeometrySubType(Geometry.SUBTYPES.GEOM3D);
572
        ID_FIELD_GEOMETRY = attr.getIndex();
573

    
574
        featureType.setDefaultGeometryAttributeName(NAME_FIELD_GEOMETRY);
575

    
576
        MAX_FIELD_ID = featureType.size() - 1;
577

    
578
        List types = new ArrayList();
579
        types.add(featureType);
580

    
581
        return types;
582
    }
583

    
584
    public class Reader {
585

    
586
        private File file;
587
        private IProjection projection;
588
        private List types;
589
        private LegendBuilder leyendBuilder;
590
        private AbstractMemoryStoreProvider store;
591
        private Envelope envelope;
592

    
593
        public Reader initialice(AbstractMemoryStoreProvider store, File file,
594
                IProjection projection,
595
                LegendBuilder leyendBuilder) {
596
            this.store = store;
597
            this.file = file;
598
            this.projection = projection;
599
            this.leyendBuilder = leyendBuilder;
600
            if (leyendBuilder != null) {
601
                leyendBuilder.initialize(store);
602
            }
603
            return this;
604
        }
605

    
606
        public Envelope getEnvelope() {
607
            return this.envelope;
608
        }
609

    
610
        public void begin(FeatureStoreProviderServices store) {
611

    
612
            types = getFeatureTypes(store);
613

    
614
            if (leyendBuilder != null) {
615
                leyendBuilder.begin();
616
            }
617

    
618
        }
619

    
620
        public void end() {
621
            if (leyendBuilder != null) {
622
                leyendBuilder.end();
623
            }
624
        }
625

    
626
        public List getTypes() {
627
            return types;
628
        }
629

    
630
        public EditableFeatureType getDefaultType() {
631
            return (EditableFeatureType) types.get(0);
632
        }
633

    
634
//                private Double toDouble(String value) {
635
//                        if (value == null) {
636
//                                return Double.valueOf(0);
637
//                        }
638
//                        return Double.valueOf(value);
639
//                }
640
        public void load() throws DataException, CreateEnvelopeException {
641
            switch (getDGNParameters().getLoadMode()) {
642
                case LOAD_MODE_PLAIN:
643
                default:
644
                    load_plain();
645
                    break;
646
                case LOAD_MODE_GROUP1:
647
                    load_group1();
648
                    break;
649
            }
650
        }
651

    
652
        public void load_plain() throws DataException {
653

    
654
            FileWriter xmlfw = null;
655
            BufferedWriter xmlbfw = null;
656

    
657
            this.envelope = null;
658

    
659
            boolean ignoreZs = getDGNParameters().ignoreZs();
660
            boolean useZAsElevation = getDGNParameters().useZAsElevation();
661
            boolean applyRoundToElevation = getDGNParameters().getApplyRoundToElevation();
662
            double elevationFactor = getDGNParameters().geElevationFactor();
663

    
664
            try {
665
                if (getDGNParameters().getXMLFile() != null) {
666
                    File xmlfile = getDGNParameters().getXMLFile();
667
                    try {
668
                        xmlfw = new FileWriter(xmlfile);
669
                        xmlbfw = new BufferedWriter(xmlfw);
670

    
671
                    } catch (Exception ex) {
672
                        xmlfw = null;
673
                        xmlbfw = null;
674
                        logger.warn("Can't open xmfile for output (" + xmlfile.getAbsolutePath() + "'.", ex);
675
                    }
676
                    if (xmlbfw != null) {
677
                        try {
678
                            xmlbfw.write("<DGN>\n");
679
                        } catch (IOException ex) {
680
                            logger.warn("Can't write to the xml file.", ex);
681
                        }
682
                    }
683

    
684
                }
685

    
686
                DGNReader dgnReader = new DGNReader(file.getAbsolutePath(), getDGNParameters().logErrors());
687

    
688
                if (dgnReader.getInfo().dimension == 2 || getDGNParameters().ignoreZs()) {
689
                    envelope = geomManager.createEnvelope(SUBTYPES.GEOM2D);
690
                } else {
691
                    envelope = geomManager.createEnvelope(SUBTYPES.GEOM3D);
692
                }
693

    
694
                FeatureType type = getDefaultType().getNotEditableCopy();
695

    
696
                int counterOfElement = 0;
697
                DGNElemComplexHeader parentElement = null;
698

    
699
                double zvalue = 0;
700

    
701
                for (int id = 0; id < dgnReader.getNumEntities(); id++) {
702
                    dgnReader.DGNGotoElement(id);
703

    
704
                    DGNElemCore elemento = dgnReader.DGNReadElement();
705
                    if (elemento == null) {
706
                        continue;
707
                    }
708

    
709
                    if (parentElement != null) {
710
                        counterOfElement++;
711
                        if (parentElement.getNumElements() < counterOfElement) {
712
                            // Ya hemos terminado de recorrer el elemento complejo.
713
                            parentElement = null;
714
                        }
715
                    }
716

    
717
                    if (xmlbfw != null) {
718
                        // Volcamos el elemnto del DGN a fichero en formato XML
719
                        try {
720
                            xmlbfw.write(dgnReader.DGNDumpElement(dgnReader.getInfo(), elemento));
721
                        } catch (IOException ex) {
722
                            logger.warn("Can't write to the xml file.", ex);
723
                        }
724
                    }
725

    
726
                    if (elemento.isDeleted()) {
727
//                      Saltamos los elementos borrados.
728
                        continue;
729
                    }
730

    
731
                    FeatureProvider data = createFeatureProvider(type);
732

    
733
                    data.set(ID_FIELD_ID, elemento.getID());
734
                    data.set(ID_FIELD_TYPE, elemento.getType());
735
                    data.set(ID_FIELD_STYPE, elemento.getSType());
736
                    data.set(ID_FIELD_LEVEL, elemento.getLevelAsString());
737
                    data.set(ID_FIELD_COLOR, elemento.getColor());
738
                    data.set(ID_FIELD_FILLCOLOR, elemento.getShapeFillColor());
739
                    data.set(ID_FIELD_ENTITY, elemento.getEntityName());
740
                    data.set(ID_FIELD_STYLE, elemento.getStyle());
741
                    data.set(ID_FIELD_WEIGHT, elemento.getWeight());
742
                    data.set(ID_FIELD_GROUP, elemento.getGroup());
743
                    data.set(ID_FIELD_ELEVATION, elemento.getElevation());
744
                    data.set(ID_FIELD_ISCOMPLEXSHAPEHEADER, elemento.isComplexShapeHeader());
745
                    data.set(ID_FIELD_ISSHAPE, elemento.isShape());
746
                    data.set(ID_FIELD_ISHOLE, elemento.isHole());
747
                    data.set(ID_FIELD_ISCOMPLEX, elemento.isComplex());
748
                    data.set(ID_FIELD_HEIGHTTEXT, 0);
749
                    data.set(ID_FIELD_HEIGHTTEXTRAW, 0);
750
                    data.set(ID_FIELD_ROTATIONTEXT, 0);
751
                    data.set(ID_FIELD_TEXT, null);
752
                    data.set(ID_FIELD_SCALE, dgnReader.getInfo().scale);
753
                    data.set(ID_FIELD_DATA, elemento.getDataAsHexadecimal());
754
                    
755
                    if (parentElement == null) {
756
                        data.set(ID_FIELD_PARENT, elemento.getID());
757
                    } else {
758
                        data.set(ID_FIELD_PARENT, parentElement.getID());
759
                    }
760
                    data.set(ID_FIELD_LINKS_COUNT, dgnReader.DGNGetLinkageCount(elemento));
761

    
762
                    DGNLink dgnlink = dgnReader.DGNGetLinkage(elemento,
763
                            getDGNParameters().getLinkFilterIndex(),
764
                            getDGNParameters().getLinkFilterType(),
765
                            getDGNParameters().getLinkFilterEntity(),
766
                            getDGNParameters().getLinkFilterMS(),
767
                            getDGNParameters().getLinkFilterDataAsPattern()
768
                    );
769
                    if (dgnlink != null) {
770
                        data.set(ID_FIELD_LINK_INDEX, dgnlink.getIndex());
771
                        data.set(ID_FIELD_LINK_TYPE, dgnlink.getType());
772
                        data.set(ID_FIELD_LINK_ENTITY, dgnlink.getEntityCode());
773
                        data.set(ID_FIELD_LINK_MS, dgnlink.getMSLink());
774
                        data.set(ID_FIELD_LINK_LENGTH, dgnlink.getLength());
775
                        data.set(ID_FIELD_LINK_DATA, dgnlink.getDataAsHexadecimal());
776
                    } else {
777
                        data.set(ID_FIELD_LINK_INDEX, -1);
778
                        data.set(ID_FIELD_LINK_TYPE, 0);
779
                        data.set(ID_FIELD_LINK_ENTITY, 0);
780
                        data.set(ID_FIELD_LINK_MS, 0);
781
                        data.set(ID_FIELD_LINK_LENGTH, 0);
782
                        data.set(ID_FIELD_LINK_DATA, "");
783
                    }
784

    
785
//                    if( elemento.getStyle()==3 && elemento.getLevel()==23 ) {
786
//                        logger.info("Un isopaco...");
787
//                    }
788
                    zvalue = 0;
789
                    try {
790
                        switch (elemento.stype) {
791
                            case DGNFileHeader.DGNST_COMPLEX_HEADER:
792
                                parentElement = (DGNElemComplexHeader) elemento;
793
                                counterOfElement = 0;
794
                                break;
795

    
796
                            case DGNFileHeader.DGNST_MULTIPOINT:
797
                                DGNElemMultiPoint dgnmultipoint = (DGNElemMultiPoint) elemento;
798
                                if (dgnmultipoint.isPoint()) {
799
                                    DGNPoint p = dgnmultipoint.getPoint(0);
800
                                    Point point = createPoint(p.getX(), p.getY(), ignoreZs ? 0 : p.getZ());
801
                                    data.setDefaultGeometry(point);
802
                                    zvalue = p.getZ();
803
                                } else {
804
                                    OrientablePrimitive geom = null;
805
                                    if (dgnmultipoint.isPolygon()) {
806
                                        geom = geomManager.createSurface(getGeometrySubType(dgnmultipoint));
807
                                    } else {
808
                                        geom = geomManager.createCurve(getGeometrySubType(dgnmultipoint));
809
                                    }
810

    
811
                                    // Si es una curva nos saltamos los dos primeros y los dos ultimos vertices.
812
                                    int first = 0;
813
                                    int numVertices = dgnmultipoint.getNumVertices();
814
                                    if (dgnmultipoint.isCurve()) {
815
                                        first = 2;
816
                                        numVertices = dgnmultipoint.getNumVertices() - 2;
817
                                    }
818

    
819
                                    if (dgnmultipoint.isHole()) {
820
                                        // Invertimos el orden porque es un agujero
821
                                        for (int i = numVertices - 2; i >= first; i--) {
822
                                            DGNPoint p = dgnmultipoint.getVertex(i);
823
                                            zvalue = p.getZ();
824
                                            addVertex(geom, p.getX(), p.getY(), ignoreZs ? 0 : zvalue);
825
                                        }
826
                                    } else {
827
                                        for (int i = first; i < numVertices; i++) {
828
                                            DGNPoint p = dgnmultipoint.getVertex(i);
829
                                            zvalue = p.getZ();
830
                                            addVertex(geom,p.getX(), p.getY(), ignoreZs ? 0 : zvalue);
831
                                        }
832
                                    }
833
                                    data.setDefaultGeometry(geom);
834
                                }
835
                                break;
836

    
837
                            case DGNFileHeader.DGNST_ARC:
838
                                DGNElemArc dgnarc = (DGNElemArc) elemento;
839

    
840
                                // La definici?n de arco de MicroStation es distinta a
841
                                // la de Java.
842
                                // En el dgn el origin se entiende que es el centro del
843
                                // arco,
844
                                // y a la hora de crear un Arc2D las 2 primeras
845
                                // coordenadas son
846
                                // la esquina inferior izquierda del rect?ngulo que
847
                                // rodea al arco.
848
                                // 1.- Creamos la elipse sin rotaci?n.
849
                                // 2.- Creamos el arco
850
                                // 3.- Rotamos el resultado
851
                                AffineTransform mT = AffineTransform.getRotateInstance(
852
                                        Math.toRadians(dgnarc.rotation), dgnarc.origin.x,
853
                                        dgnarc.origin.y);
854

    
855
                                // mT.preConcatenate(AffineTransform.getScaleInstance(100.0,100.0));
856
                                Arc2D.Double elArco = new Arc2D.Double(
857
                                        dgnarc.origin.x - dgnarc.primary_axis,
858
                                        dgnarc.origin.y - dgnarc.secondary_axis,
859
                                        2.0 * dgnarc.primary_axis,
860
                                        2.0 * dgnarc.secondary_axis,
861
                                        -dgnarc.startang,
862
                                        -dgnarc.sweepang,
863
                                        Arc2D.OPEN);
864

    
865
                                zvalue = dgnarc.origin.getZ();
866

    
867
                                GeneralPathX elShapeArc = new GeneralPathX(elArco.getPathIterator(null));
868

    
869
                                // Transformamos el GeneralPahtX porque si transformamos
870
                                // elArco nos lo convierte
871
                                // a GeneralPath y nos guarda las coordenadas en float,
872
                                // con la correspondiente p?rdida de precisi?n
873
                                elShapeArc.transform(mT);
874

    
875
                                Geometry geom = null;
876
                                if (dgnarc.isSurface()) {
877
                                    geom = geomManager.createSurface(elShapeArc,getGeometrySubType(dgnarc));
878
                                } else {
879
                                    geom = geomManager.createCurve(elShapeArc,getGeometrySubType(dgnarc));
880
                                }
881
                                data.setDefaultGeometry(geom);
882
                                break;
883

    
884
                            case DGNFileHeader.DGNST_TEXT:
885
                                DGNElemText dgntext = (DGNElemText) elemento;
886
                                zvalue = dgntext.getPoint().getZ();
887
                                Point point = createPoint(
888
                                        dgntext.getPoint().getX(),
889
                                        dgntext.getPoint().getY(),
890
                                        ignoreZs ? 0 : zvalue
891
                                );
892
                                data.set(ID_FIELD_HEIGHTTEXT, dgntext.getHeight());
893
                                data.set(ID_FIELD_HEIGHTTEXTRAW, dgntext.getRawHeight());
894
                                data.set(ID_FIELD_ROTATIONTEXT, dgntext.getRotation());
895
                                data.set(ID_FIELD_TEXT, dgntext.getText());
896

    
897
                                data.setDefaultGeometry(point);
898
                                break;
899

    
900
                            default:
901
                                break;
902

    
903
                        } // switch
904
                    } catch (Exception ex) {
905
                        logger.warn("Can't process element", ex);
906
                    }
907
                    if (useZAsElevation) {
908
                        if (!DGNStoreProvider.equals(elevationFactor, 1, 0.00001)) {
909
                            zvalue = zvalue * elevationFactor;
910
                        }
911
                        if (applyRoundToElevation) {
912
                            zvalue = Math.round(zvalue);
913
                        }
914
                        data.set(ID_FIELD_ELEVATION, zvalue);
915
                    }
916
                    addFeature(data, dgnReader);
917
                } // for
918

    
919
                if (xmlbfw != null) {
920
                    try {
921
                        xmlbfw.write("</DGN>\n");
922
                    } catch (IOException ex) {
923
                        logger.warn("Can't write to the xml file.", ex);
924
                    }
925
                }
926

    
927
            } catch (Exception ex) {
928
                logger.warn("Can't process DGN file '" + getFullName() + ".", ex);
929
                throw new LoadException(ex, getFullName());
930
            } finally {
931
                IOUtils.closeQuietly(xmlbfw);
932
                IOUtils.closeQuietly(xmlfw);
933
            }
934

    
935
        }
936

    
937
        private int getGeometrySubType(DGNElemCore element) {
938
            if( getDGNParameters().force2D() ) {
939
                return Geometry.SUBTYPES.GEOM2D;
940
            }
941
            return element.is3D()? Geometry.SUBTYPES.GEOM3D : Geometry.SUBTYPES.GEOM2D;
942
        }
943
        
944
        private void addVertex(OrientablePrimitive geom, double x, double y, double z) {
945
            if( geom.getDimension()==2 ) { 
946
                geom.addVertex(x, y);
947
            } else {
948
                geom.addVertex(x, y, z);
949
            }
950
        }
951
        
952
        private void fillRow(Object[] row, DGNElemCore elemento, DGNElemComplexHeader parentElement, DGNReader dgnReader) {
953
            row[ID_FIELD_HEIGHTTEXT] = new Double(0);
954
            row[ID_FIELD_HEIGHTTEXTRAW] = new Double(0);
955
            row[ID_FIELD_ROTATIONTEXT] = new Double(0);
956
            row[ID_FIELD_TEXT] = null;
957

    
958
            row[ID_FIELD_ID] = elemento.getID();
959
            row[ID_FIELD_TYPE] = elemento.getType();
960
            row[ID_FIELD_STYPE] = elemento.getSType();
961
            row[ID_FIELD_LEVEL] = elemento.getLevelAsString();
962
            row[ID_FIELD_COLOR] = elemento.getColor();
963
            row[ID_FIELD_FILLCOLOR] = elemento.getShapeFillColor();
964
            row[ID_FIELD_ENTITY] = elemento.getEntityName();
965
            row[ID_FIELD_STYLE] = elemento.getStyle();
966
            row[ID_FIELD_WEIGHT] = elemento.getWeight();
967
            row[ID_FIELD_GROUP] = elemento.getGroup();
968
            row[ID_FIELD_ELEVATION] = elemento.getElevation();
969
            row[ID_FIELD_ISCOMPLEXSHAPEHEADER] = elemento.isComplexShapeHeader();
970
            row[ID_FIELD_ISSHAPE] = elemento.isShape();
971
            row[ID_FIELD_ISHOLE] = elemento.isHole();
972
            row[ID_FIELD_ISCOMPLEX] = elemento.isComplex();
973
            row[ID_FIELD_PARENT] = elemento.getID();
974
            if (parentElement != null) {
975
                row[ID_FIELD_PARENT] = parentElement.getID();
976
            }
977
            row[ID_FIELD_SCALE] = dgnReader.getInfo().scale;
978

    
979
        }
980

    
981
        public void load_group1() throws DataException, CreateEnvelopeException {
982

    
983
            this.envelope = null;
984

    
985
            FileWriter xmlfw = null;
986
            BufferedWriter xmlbfw = null;
987
            if (getDGNParameters().getXMLFile() != null) {
988
                File xmlfile = getDGNParameters().getXMLFile();
989
                try {
990
                    xmlfw = new FileWriter(xmlfile);
991
                    xmlbfw = new BufferedWriter(xmlfw);
992

    
993
                } catch (Exception ex) {
994
                    xmlfw = null;
995
                    xmlbfw = null;
996
                    logger.warn("Can't open xmfile for output (" + xmlfile.getAbsolutePath() + "'.", ex);
997
                }
998
                if (xmlbfw != null) {
999
                    try {
1000
                        xmlbfw.write("<DGN>\n");
1001
                    } catch (IOException ex) {
1002
                        logger.warn("Can't write to the xml file.", ex);
1003
                    }
1004
                }
1005

    
1006
            }
1007
            DGNReader dgnReader = new DGNReader(file.getAbsolutePath());
1008
            if (dgnReader.getInfo().dimension == 2) {
1009
                envelope = geomManager.createEnvelope(Geometry.SUBTYPES.GEOM2D);
1010
            } else {
1011
                envelope = geomManager.createEnvelope(SUBTYPES.GEOM3D);
1012
            }
1013

    
1014
            FeatureType type = getDefaultType().getNotEditableCopy();
1015
            int fTypeSize = type.size();
1016
            Object[] auxRow = new Object[fTypeSize];
1017
            Object[] cellRow = new Object[fTypeSize];
1018
            Object[] complexRow = new Object[fTypeSize];
1019

    
1020
            boolean bElementoCompuesto = false;
1021
            boolean bEsPoligono = false;
1022
            boolean bInsideCell = false;
1023
            boolean bFirstHoleEntity = false;
1024
            boolean bConnect = false; // Se usa para que los pol?gonos cierren
1025
            // bien cuando son formas compuestas
1026
//                        int contadorSubElementos = 0;
1027
//                        int numSubElementos = 0;
1028
            int complex_index_fill_color = -1;
1029
            int nClass; // Para filtrar los elementos de construcci?n, etc.
1030
            GeneralPathX elementoCompuesto = new GeneralPathX(
1031
                    GeneralPathX.WIND_EVEN_ODD);
1032

    
1033
            int counterOfElement = 0;
1034
            DGNElemComplexHeader parentElement = null;
1035

    
1036
            for (int id = 0; id < dgnReader.getNumEntities(); id++) {
1037
                dgnReader.DGNGotoElement(id);
1038

    
1039
                DGNElemCore elemento = dgnReader.DGNReadElement();
1040
                if (parentElement != null) {
1041
                    counterOfElement++;
1042
                    if (parentElement.getNumElements() < counterOfElement) {
1043
                        // Ya hemos terminado de recorrer el elemento complejo.
1044
                        parentElement = null;
1045
                    }
1046
                }
1047

    
1048
                if (xmlbfw != null && elemento != null) {
1049
                    // Volcamos el elemnto del DGN a fichero en formato XML
1050
                    try {
1051
                        xmlbfw.write(dgnReader.DGNDumpElement(dgnReader.getInfo(), elemento));
1052
                    } catch (IOException ex) {
1053
                        logger.warn("Can't write to the xml file.", ex);
1054
                    }
1055
                }
1056

    
1057
                nClass = 0;
1058
                fillRow(auxRow, elemento, parentElement, dgnReader);
1059
                auxRow[ID_FIELD_HEIGHTTEXT] = new Double(0);
1060
                auxRow[ID_FIELD_ROTATIONTEXT] = new Double(0);
1061
                auxRow[ID_FIELD_TEXT] = null;
1062

    
1063
                if (elemento.properties != 0) {
1064
                    nClass = elemento.properties & DGNFileHeader.DGNPF_CLASS;
1065
                }
1066

    
1067
                if ((elemento != null) && (elemento.deleted == 0)
1068
                        && (nClass == 0)) // Leer un elemento
1069
                {
1070

    
1071
                    // if ((elemento.element_id > 3800) && (elemento.element_id
1072
                    // < 3850))
1073
                    // dgnReader.DGNDumpElement(dgnReader.getInfo(),elemento,"");
1074
                    if ((elemento.stype == DGNFileHeader.DGNST_MULTIPOINT)
1075
                            || (elemento.stype == DGNFileHeader.DGNST_ARC)
1076
                            || (elemento.stype == DGNFileHeader.DGNST_CELL_HEADER)
1077
                            || (elemento.stype == DGNFileHeader.DGNST_SHARED_CELL_DEFN)
1078
                            || (elemento.stype == DGNFileHeader.DGNST_COMPLEX_HEADER)) {
1079
                        if (elemento.complex != 0) {
1080
                            bElementoCompuesto = true;
1081
                        } else {
1082
                            if (bElementoCompuesto) {
1083
                                if (bInsideCell) {
1084
                                    auxRow[ID_FIELD_ENTITY] = cellRow[ID_FIELD_ENTITY];
1085
                                } else {
1086
                                    auxRow = complexRow;
1087
                                }
1088
                                addShape(createMultiCurve(elementoCompuesto),
1089
                                        auxRow, type, dgnReader);
1090

    
1091
                                if (bEsPoligono) {
1092
                                    if (complex_index_fill_color != -1) {
1093
                                        auxRow[ID_FIELD_COLOR] = complex_index_fill_color;
1094
                                    }
1095

    
1096
                                    addShape(
1097
                                            createMultiSurface(elementoCompuesto),
1098
                                            auxRow, type, dgnReader);
1099
                                }
1100

    
1101
                                elementoCompuesto = new GeneralPathX(
1102
                                        GeneralPathX.WIND_EVEN_ODD);
1103
                            }
1104

    
1105
                            bElementoCompuesto = false;
1106
                            bEsPoligono = false;
1107
                            bConnect = false;
1108

    
1109
                            bInsideCell = false;
1110
                        }
1111
                    }
1112

    
1113
                    switch (elemento.stype) {
1114
                        case DGNFileHeader.DGNST_SHARED_CELL_DEFN:
1115
                            bInsideCell = true;
1116
                            fillRow(cellRow, elemento, parentElement, dgnReader);
1117
                            cellRow[ID_FIELD_ID] = elemento.element_id;
1118
                            cellRow[ID_FIELD_LAYER] = String.valueOf(elemento.level);
1119
                            cellRow[ID_FIELD_COLOR] = elemento.color;
1120
                            cellRow[ID_FIELD_ENTITY] = "Shared Cell";
1121

    
1122
                            break;
1123

    
1124
                        case DGNFileHeader.DGNST_CELL_HEADER:
1125
                            bInsideCell = true;
1126

    
1127
                            fillRow(cellRow, elemento, parentElement, dgnReader);
1128
                            cellRow[ID_FIELD_ID] = elemento.element_id;
1129
                            cellRow[ID_FIELD_LAYER] = String.valueOf(elemento.level);
1130
                            cellRow[ID_FIELD_COLOR] = elemento.color;
1131
                            cellRow[ID_FIELD_ENTITY] = "Cell";
1132
                            complex_index_fill_color = dgnReader
1133
                                    .DGNGetShapeFillInfo(elemento);
1134
                            break;
1135

    
1136
                        case DGNFileHeader.DGNST_COMPLEX_HEADER:
1137

    
1138
                            // bElementoCompuesto = true;
1139
//                                                contadorSubElementos = 0;
1140
                            DGNElemComplexHeader psComplexHeader = (DGNElemComplexHeader) elemento;
1141

    
1142
                            parentElement = psComplexHeader;
1143
                            counterOfElement = parentElement.getNumElements();
1144

    
1145
//                                                numSubElementos = psComplexHeader.numelems;
1146
                            fillRow(complexRow, elemento, parentElement, dgnReader);
1147
                            complexRow[ID_FIELD_ID] = elemento.element_id;
1148
                            complexRow[ID_FIELD_LAYER] = String.valueOf(elemento.level);
1149
                            complexRow[ID_FIELD_COLOR] = elemento.color;
1150
                            complexRow[ID_FIELD_ENTITY] = "Complex";
1151

    
1152
                            if (psComplexHeader.type == DGNFileHeader.DGNT_COMPLEX_SHAPE_HEADER) {
1153
                                bEsPoligono = true;
1154

    
1155
                                // Si es un agujero, no conectamos con el anterior
1156
                                if ((psComplexHeader.properties & 0x8000) != 0) {
1157
                                    bFirstHoleEntity = true;
1158
                                } else {
1159
                                    // Miramos si tiene color de relleno
1160
                                    // complex_index_fill_color = -1;
1161
                                    // if (elemento.attr_bytes > 0) {
1162
                                    complex_index_fill_color = dgnReader
1163
                                            .DGNGetShapeFillInfo(elemento);
1164

    
1165
                                    // }
1166
                                }
1167

    
1168
                                bConnect = true;
1169
                            } else {
1170
                                bEsPoligono = false;
1171
                                bConnect = false;
1172
                            }
1173

    
1174
                            break;
1175

    
1176
                        case DGNFileHeader.DGNST_MULTIPOINT:
1177

    
1178
                            // OJO: Si lo que viene en este multipoint es un
1179
                            // elemento con type=11 (curve), se trata de una
1180
                            // "parametric
1181
                            // spline curve". La vamos a tratar como si no fuera
1182
                            // curva, pero seg?n la documentaci?n, los 2 primeros
1183
                            // puntos
1184
                            // y los 2 ?ltimos puntos definen "endpoint derivatives"
1185
                            // y NO se muestran.
1186
                            // TODAV?A HAY UN PEQUE?O FALLO CON EL FICHERO
1187
                            // dgn-sample.dgn, pero lo dejo por ahora.
1188
                            // Es posible que tenga que ver con lo de los arcos
1189
                            // (arco distorsionado), que
1190
                            // todav?a no est? metido.
1191
                            DGNElemMultiPoint psLine = (DGNElemMultiPoint) elemento;
1192
                            fillRow(auxRow, elemento, parentElement, dgnReader);
1193
                            auxRow[ID_FIELD_ID] = elemento.element_id;
1194
                            auxRow[ID_FIELD_ENTITY] = "Multipoint";
1195
                            auxRow[ID_FIELD_LAYER] = String.valueOf(elemento.level);
1196
                            auxRow[ID_FIELD_COLOR] = elemento.color;
1197

    
1198
                            if ((psLine.num_vertices == 2)
1199
                                    && (psLine.vertices[0].x == psLine.vertices[1].x)
1200
                                    && (psLine.vertices[0].y == psLine.vertices[1].y)) {
1201
                                auxRow[ID_FIELD_ENTITY] = "Point";
1202
                                addShape(
1203
                                        createPoint(psLine.vertices[0].x,
1204
                                                psLine.vertices[0].y,
1205
                                                psLine.vertices[0].z), auxRow,
1206
                                        type, dgnReader);
1207
                            } else {
1208
                                GeneralPathX elShape = new GeneralPathX(
1209
                                        GeneralPathX.WIND_EVEN_ODD);
1210

    
1211
                                if (psLine.type == DGNFileHeader.DGNT_CURVE) {
1212
                                    psLine.num_vertices = psLine.num_vertices - 4;
1213

    
1214
                                    for (int aux_n = 0; aux_n < psLine.num_vertices; aux_n++) {
1215
                                        psLine.vertices[aux_n] = psLine.vertices[aux_n + 2];
1216
                                    }
1217
                                }
1218

    
1219
                                if ((psLine.type == DGNFileHeader.DGNT_SHAPE)
1220
                                        && ((psLine.properties & 0x8000) != 0)) {
1221
                                    // Invertimos el orden porque es un agujero
1222
                                    elShape
1223
                                            .moveTo(
1224
                                                    psLine.vertices[psLine.num_vertices - 1].x,
1225
                                                    psLine.vertices[psLine.num_vertices - 1].y);
1226

    
1227
                                    for (int i = psLine.num_vertices - 2; i >= 0; i--) {
1228
                                        elShape.lineTo(psLine.vertices[i].x,
1229
                                                psLine.vertices[i].y);
1230
                                    }
1231
                                } else {
1232
                                    elShape.moveTo(psLine.vertices[0].x,
1233
                                            psLine.vertices[0].y);
1234

    
1235
                                    for (int i = 1; i < psLine.num_vertices; i++) {
1236
                                        elShape.lineTo(psLine.vertices[i].x,
1237
                                                psLine.vertices[i].y);
1238
                                    }
1239
                                }
1240

    
1241
                                if ((psLine.vertices[0].x == psLine.vertices[psLine.num_vertices - 1].x)
1242
                                        && (psLine.vertices[0].y == psLine.vertices[psLine.num_vertices - 1].y)) {
1243
                                    // Lo a?adimos tambi?n como pol?gono
1244
                                    bEsPoligono = true;
1245

    
1246
                                    // Miramos si tiene color de relleno
1247
                                    if (elemento.attr_bytes > 0) {
1248
                                        elemento.color = dgnReader
1249
                                                .DGNGetShapeFillInfo(elemento);
1250

    
1251
                                        if (elemento.color != -1) {
1252
                                            auxRow[ID_FIELD_COLOR] = elemento.color;
1253
                                        }
1254
                                    }
1255

    
1256
                                    if (elemento.complex == 0) {
1257
                                        addShape(createSurface(elShape), auxRow,
1258
                                                type, dgnReader);
1259
                                    }
1260
                                }
1261

    
1262
                                if (elemento.complex != 0) {
1263
                                    // Si es un agujero o
1264
                                    // es la primera entidad del agujero, lo
1265
                                    // a?adimos sin unir al anterior
1266
                                    if (bFirstHoleEntity
1267
                                            || ((psLine.type == DGNFileHeader.DGNT_SHAPE) && ((psLine.properties & 0x8000) != 0))) {
1268
                                        elementoCompuesto.append(elShape.getPathIterator(null), false);
1269
                                        bFirstHoleEntity = false;
1270
                                    } else {
1271
                                        elementoCompuesto.append(elShape.getPathIterator(null), bConnect);
1272
                                    }
1273
                                } else {
1274
                                    addShape(createMultiCurve(elShape), auxRow,
1275
                                            type, dgnReader);
1276
                                }
1277
                            }
1278

    
1279
                            break;
1280

    
1281
                        case DGNFileHeader.DGNST_ARC:
1282

    
1283
                            // dgnReader.DGNDumpElement(dgnReader.getInfo(),
1284
                            // elemento,"");
1285
                            DGNElemArc psArc = (DGNElemArc) elemento;
1286

    
1287
                            // La definici?n de arco de MicroStation es distinta a
1288
                            // la de Java.
1289
                            // En el dgn el origin se entiende que es el centro del
1290
                            // arco,
1291
                            // y a la hora de crear un Arc2D las 2 primeras
1292
                            // coordenadas son
1293
                            // la esquina inferior izquierda del rect?ngulo que
1294
                            // rodea al arco.
1295
                            // 1.- Creamos la elipse sin rotaci?n.
1296
                            // 2.- Creamos el arco
1297
                            // 3.- Rotamos el resultado
1298
                            AffineTransform mT = AffineTransform.getRotateInstance(
1299
                                    Math.toRadians(psArc.rotation), psArc.origin.x,
1300
                                    psArc.origin.y);
1301

    
1302
                            // mT.preConcatenate(AffineTransform.getScaleInstance(100.0,100.0));
1303
                            Arc2D.Double elArco = new Arc2D.Double(psArc.origin.x
1304
                                    - psArc.primary_axis, psArc.origin.y
1305
                                    - psArc.secondary_axis,
1306
                                    2.0 * psArc.primary_axis,
1307
                                    2.0 * psArc.secondary_axis, -psArc.startang,
1308
                                    -psArc.sweepang, Arc2D.OPEN);
1309

    
1310
                            // Ellipse2D.Double elArco = new
1311
                            // Ellipse2D.Double(psArc.origin.x - psArc.primary_axis,
1312
                            // psArc.origin.y - psArc.secondary_axis,2.0 *
1313
                            // psArc.primary_axis, 2.0 * psArc.secondary_axis);
1314
                            GeneralPathX elShapeArc = new GeneralPathX(elArco.getPathIterator(null));
1315

    
1316
                            // Transformamos el GeneralPahtX porque si transformamos
1317
                            // elArco nos lo convierte
1318
                            // a GeneralPath y nos guarda las coordenadas en float,
1319
                            // con la correspondiente p?rdida de precisi?n
1320
                            elShapeArc.transform(mT);
1321

    
1322
                            if (dgnReader.getInfo().dimension == 3) {
1323
                                // Aqu? podr?amos hacer cosas con la coordenada Z
1324
                            }
1325

    
1326
                            fillRow(auxRow, elemento, parentElement, dgnReader);
1327
                            auxRow[ID_FIELD_ID] = elemento.element_id;
1328
                            auxRow[ID_FIELD_ENTITY] = "Arc";
1329
                            auxRow[ID_FIELD_LAYER] = String.valueOf(elemento.level);
1330
                            auxRow[ID_FIELD_COLOR] = elemento.color;
1331

    
1332
                            /*
1333
                             * Line2D.Double ejeMayor = new
1334
                             * Line2D.Double(psArc.origin.x - psArc.primary_axis,
1335
                             * psArc.origin.y, psArc.origin.x + psArc.primary_axis,
1336
                             * psArc.origin.y);
1337
                             *
1338
                             * lyrLines.addShape(new
1339
                             * FShape(FConstant.SHAPE_TYPE_POLYLINE, new
1340
                             * GeneralPathX(ejeMayor)), auxRow);
1341
                             */
1342
                            // lyrLines.addShape(new
1343
                            // FShape(FConstant.SHAPE_TYPE_POLYLINE, elShapeArc),
1344
                            // auxRow);
1345
                            if (elemento.complex != 0) {
1346
                                // Esto es una posible fuente de fallos si detr?s de
1347
                                // una
1348
                                // elipse vienen m?s cosas pegadas. Deber?amos
1349
                                // volver
1350
                                // a conectar una vez pasada la elipse.
1351
                                if (elemento.type == DGNFileHeader.DGNT_ELLIPSE) {
1352
                                    bConnect = false;
1353
                                }
1354

    
1355
                                // SI LA ELIPSE ES UN AGUJERO, SE A?ADE SIN PEGAR
1356
                                // Y EL ELEMENTO ES UN POLIGONO
1357
                                if (bFirstHoleEntity
1358
                                        || ((elemento.type == DGNFileHeader.DGNT_SHAPE) && ((elemento.properties & 0x8000) != 0))) {
1359
                                    elementoCompuesto.append(elShapeArc.getPathIterator(null), false);
1360
                                    bFirstHoleEntity = false;
1361
                                } else {
1362
                                    elementoCompuesto.append(elShapeArc.getPathIterator(null), bConnect);
1363
                                }
1364
                            } else {
1365
                                addShape(createMultiCurve(elShapeArc), auxRow,
1366
                                        type, dgnReader);
1367

    
1368
                                if (psArc.type == DGNFileHeader.DGNT_ELLIPSE) {
1369
                                    addShape(createSurface(elShapeArc), auxRow,
1370
                                            type, dgnReader);
1371
                                }
1372
                            }
1373

    
1374
                            break;
1375

    
1376
                        case DGNFileHeader.DGNST_TEXT:
1377

    
1378
                            DGNElemText psText = (DGNElemText) elemento;
1379
                            Geometry elShapeTxt = createPoint(psText.origin.x,
1380
                                    psText.origin.y, psText.origin.z);
1381

    
1382
                            fillRow(auxRow, elemento, parentElement, dgnReader);
1383
                            auxRow[ID_FIELD_ID] = elemento.element_id;
1384
                            auxRow[ID_FIELD_ENTITY] = "Text";
1385
                            auxRow[ID_FIELD_LAYER] = String.valueOf(elemento.level);
1386
                            auxRow[ID_FIELD_COLOR] = elemento.color;
1387
                            auxRow[ID_FIELD_HEIGHTTEXT] = psText.height_mult;
1388
                            auxRow[ID_FIELD_HEIGHTTEXTRAW] = psText.height_raw;
1389
                            auxRow[ID_FIELD_ROTATIONTEXT] = psText.rotation;
1390
                            auxRow[ID_FIELD_TEXT] = psText.string; // .trim();
1391
                            addShape(elShapeTxt, auxRow, type, dgnReader);
1392
                            break;
1393

    
1394
                        /*
1395
                         * default:
1396
                         * dgnReader.DGNDumpElement(dgnReader.getInfo(),
1397
                         * elemento, "");
1398
                         */
1399
                    } // switch
1400
                } // if
1401
            } // for
1402

    
1403
            if (bElementoCompuesto) {
1404
                if (bInsideCell) {
1405
                    auxRow = cellRow;
1406
                } else {
1407
                    auxRow = complexRow;
1408
                }
1409

    
1410
                addShape(createMultiCurve(elementoCompuesto), auxRow, type,
1411
                        dgnReader);
1412

    
1413
                if (bEsPoligono) {
1414
                    if (complex_index_fill_color != -1) {
1415
                        auxRow[ID_FIELD_COLOR] = complex_index_fill_color;
1416
                    }
1417

    
1418
                    addShape(createSurface(elementoCompuesto), auxRow, type,
1419
                            dgnReader);
1420
                }
1421
            }
1422

    
1423
            if (xmlbfw != null) {
1424
                try {
1425
                    xmlbfw.write("</DGN>\n");
1426
                } catch (IOException ex) {
1427
                    logger.warn("Can't write to the xml file.", ex);
1428
                }
1429
                IOUtils.closeQuietly(xmlbfw);
1430
                IOUtils.closeQuietly(xmlfw);
1431
            }
1432

    
1433
        }
1434

    
1435
        private Geometry createMultiSurface(GeneralPathX elementoCompuesto)
1436
                throws DataException {
1437
            try {
1438
                return geomManager.createMultiSurface(elementoCompuesto,
1439
                        SUBTYPES.GEOM2D);
1440
            } catch (CreateGeometryException e) {
1441
                throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(
1442
                        e);
1443
            }
1444

    
1445
        }
1446

    
1447
        private Point createPoint(double x, double y, double z)
1448
                throws DataException {
1449
            Point point;
1450
            int subtype = SUBTYPES.GEOM3D;
1451
            if( getDGNParameters().force2D() ) {
1452
                subtype = SUBTYPES.GEOM2D;
1453
            }
1454
            try {
1455
                point = (Point) geomManager.create(TYPES.POINT,subtype);
1456
            } catch (CreateGeometryException e) {
1457
                throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(e);
1458
            }
1459
            point.setCoordinates(new double[]{x, y, z});
1460

    
1461
            return point;
1462
        }
1463

    
1464
        private void addFeature(FeatureProvider data, DGNReader dgnReader) throws DataException {
1465

    
1466
            addFeatureProvider(data);
1467
            Geometry geometry = data.getDefaultGeometry();
1468
            if (geometry != null) {
1469
                if (this.envelope == null) {
1470
                    this.envelope = geometry.getEnvelope();
1471
                } else {
1472
                    this.envelope.add(geometry.getEnvelope());
1473
                }
1474
            }
1475
            if (this.leyendBuilder != null) {
1476
                this.leyendBuilder.process(data, dgnReader);
1477
            }
1478
        }
1479

    
1480
        private void addShape(Geometry geometry, Object[] auxRow,
1481
                FeatureType type, DGNReader dgnReader) throws DataException {
1482

    
1483
            FeatureProvider data = createFeatureProvider(type);
1484
            for (int i = 0; i < type.size(); i++) {
1485
                data.set(i, auxRow[i]);
1486
            }
1487
            data.setDefaultGeometry(geometry);
1488
            addFeature(data, dgnReader);
1489
        }
1490

    
1491
        private Geometry createMultiCurve(GeneralPathX elementoCompuesto)
1492
                throws DataException {
1493
            try {
1494
                return geomManager.createMultiCurve(elementoCompuesto,
1495
                        SUBTYPES.GEOM2D);
1496
            } catch (CreateGeometryException e) {
1497
                throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(
1498
                        e);
1499
            }
1500
        }
1501

    
1502
        private Geometry createSurface(GeneralPathX elementoCompuesto)
1503
                throws DataException {
1504
            try {
1505
                return geomManager.createCurve(elementoCompuesto,
1506
                        SUBTYPES.GEOM2D);
1507
            } catch (CreateGeometryException e) {
1508
                throw new org.gvsig.fmap.dal.feature.exception.CreateGeometryException(
1509
                        e);
1510
            }
1511

    
1512
        }
1513

    
1514
    }
1515

    
1516
    public boolean closeResourceRequested(ResourceProvider resource) {
1517
        return true;
1518
    }
1519

    
1520
    public int getOIDType() {
1521
        return DataTypes.LONG;
1522
    }
1523

    
1524
    public boolean supportsAppendMode() {
1525
        return false;
1526
    }
1527

    
1528
    public void append(FeatureProvider featureProvider) {
1529
        throw new UnsupportedOperationException();
1530
    }
1531

    
1532
    public void beginAppend() {
1533
        throw new UnsupportedOperationException();
1534
    }
1535

    
1536
    public void endAppend() {
1537
        throw new UnsupportedOperationException();
1538
    }
1539

    
1540
    public Object createNewOID() {
1541
        return new Long(counterNewsOIDs++);
1542
    }
1543

    
1544
    protected void initializeFeatureTypes() throws InitializeException {
1545
        try {
1546
            this.open();
1547
        } catch (OpenException e) {
1548
            throw new InitializeException(this.getProviderName(), e);
1549
        }
1550
    }
1551

    
1552
    public Envelope getEnvelope() throws DataException {
1553
        this.open();
1554
        return (Envelope) this.getDynValue("Envelope");
1555
    }
1556

    
1557

    
1558
    /*
1559
     * (non-Javadoc)
1560
     *
1561
     * @see
1562
     * org.gvsig.fmap.dal.resource.spi.ResourceConsumer#resourceChanged(org.
1563
     * gvsig.fmap.dal.resource.spi.ResourceProvider)
1564
     */
1565
    public void resourceChanged(ResourceProvider resource) {
1566
        this.getStoreServices().notifyChange(
1567
                DataStoreNotification.RESOURCE_CHANGED,
1568
                resource);
1569
    }
1570

    
1571
    public Object getSourceId() {
1572
        return this.getDGNParameters().getFile();
1573
    }
1574

    
1575
    public String getName() {
1576
        String name = this.getDGNParameters().getFile().getName();
1577
        int n = name.lastIndexOf(".");
1578
        if (n < 1) {
1579
            return name;
1580
        }
1581
        return name.substring(0, n);
1582
    }
1583

    
1584
    public String getFullName() {
1585
        return this.getDGNParameters().getFile().getAbsolutePath();
1586
    }
1587

    
1588
    public ResourceProvider getResource() {
1589
        return resource;
1590
    }
1591

    
1592
    public static boolean equals(double a, double b, double precision) {
1593
        double v = Math.abs(a - b);
1594
        return v < precision;
1595
    }
1596
}