Statistics
| Revision:

root / org.gvsig.legend.urbanhorizontalsignage / trunk / org.gvsig.legend.urbanhorizontalsignage / org.gvsig.legend.urbanhorizontalsignage.lib / org.gvsig.legend.urbanhorizontalsignage.lib.impl / src / main / java / org / gvsig / legend / urbanhorizontalsignage / lib / impl / DefaultUrbanHorizontalSignageManager.java @ 5130

History | View | Annotate | Download (16.7 KB)

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

    
25
import java.util.ArrayList;
26
import java.util.Iterator;
27
import java.util.List;
28
import org.apache.commons.lang3.tuple.MutablePair;
29
import org.gvsig.fmap.geom.Geometry;
30
import static org.gvsig.fmap.geom.Geometry.JOIN_STYLE_BEVEL;
31
import static org.gvsig.fmap.geom.Geometry.JOIN_STYLE_MITRE;
32
import static org.gvsig.fmap.geom.Geometry.JOIN_STYLE_ROUND;
33
import org.gvsig.fmap.geom.GeometryLocator;
34
import org.gvsig.fmap.geom.GeometryManager;
35
import org.gvsig.fmap.geom.aggregate.MultiLine;
36
import org.gvsig.fmap.geom.aggregate.MultiPolygon;
37
import org.gvsig.fmap.geom.exception.CreateGeometryException;
38
import org.gvsig.fmap.geom.operation.GeometryOperationException;
39
import org.gvsig.fmap.geom.operation.GeometryOperationNotSupportedException;
40
import org.gvsig.fmap.geom.primitive.Line;
41
import org.gvsig.fmap.geom.primitive.Point;
42
import org.gvsig.fmap.geom.primitive.Primitive;
43
import org.gvsig.fmap.geom.type.GeometryType;
44
import org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData;
45
import static org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData.CONTINUITY_MODE_CONT;
46
import static org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData.CONTINUITY_MODE_CONT_CONT;
47
import static org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData.CONTINUITY_MODE_CONT_DISC;
48
import static org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData.CONTINUITY_MODE_DISC;
49
import static org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData.CONTINUITY_MODE_DISC_CONT;
50
import static org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageData.CONTINUITY_MODE_DISC_DISC;
51
import org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageLegend;
52
import org.gvsig.legend.urbanhorizontalsignage.lib.api.UrbanHorizontalSignageManager;
53
import org.slf4j.LoggerFactory;
54

    
55
public class DefaultUrbanHorizontalSignageManager implements UrbanHorizontalSignageManager {
56

    
57
    private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(DefaultUrbanHorizontalSignageManager.class);
58

    
59
    @Override
60
    public UrbanHorizontalSignageLegend create() {
61
        return new DefaultUrbanHorizontalSignageLegend();
62
    }
63

    
64
    @Override
65
    public Class<? extends UrbanHorizontalSignageLegend> getLegendClass() {
66
        return DefaultUrbanHorizontalSignageLegend.class;
67
    }
68

    
69
    @Override
70
    public UrbanHorizontalSignageData createUrbanHorizontalSignageData() {
71
        return new DefaultUrbanHorizontalSignageData();
72
    }
73

    
74
    @Override
75
    public void calculateGeometries(Geometry originalGeometry, UrbanHorizontalSignageData data) {
76
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
77
        try {
78
            MultiPolygon segments = geomManager.createMultiPolygon(originalGeometry.getGeometryType().getSubType());
79
            MultiPolygon holes = geomManager.createMultiPolygon(originalGeometry.getGeometryType().getSubType());
80
            MultiLine lines = originalGeometry.toLines();
81
            final double offsetValueInMeters = data.getGapWidth()/2.0+data.getWidth()/2.0;
82
            final double bufferValueInMeters = data.getWidth() / 2.0;
83
            for (Geometry geom : lines) {
84
                Line line = (Line) geom;
85
                switch (data.getContinuity()) {
86
                    case CONTINUITY_MODE_CONT:
87
                    default:
88
                        Geometry buffer = line.buffer(
89
                                bufferValueInMeters,
90
                                data.isRoundVertex() ? JOIN_STYLE_ROUND : JOIN_STYLE_MITRE,
91
                                true
92
                        );
93
                        segments.addPrimitives(buffer);
94
                        break;
95
                    
96
                    case CONTINUITY_MODE_DISC:
97
                        SplittedLine splittedLine = splitLine(line, data.getSegmentsLength(), data.getHolesLength());
98
                        List<Line> splittedSegments = splittedLine.getSegments();
99
                        List<Line> splittedHoles = splittedLine.getHoles();
100
                        for (Line segment : splittedSegments) {
101
                            buffer = segment.buffer(bufferValueInMeters,
102
                                    data.isRoundVertex() ? JOIN_STYLE_ROUND : JOIN_STYLE_MITRE,
103
                                    true
104
                            );
105
                            segments.addPrimitives(buffer);
106
                        }
107
                        for (Line hole : splittedHoles) {
108
                            buffer = hole.buffer(
109
                                    bufferValueInMeters,
110
                                    data.isRoundVertex() ? JOIN_STYLE_ROUND : JOIN_STYLE_MITRE,
111
                                    true
112
                            );
113
                            holes.addPrimitives(buffer);
114
                        }
115
                        break;
116
                        
117
                    case CONTINUITY_MODE_CONT_CONT:
118
                        //Left
119
                        addOffsetedAndBufferedSegment(segments, line, -offsetValueInMeters, bufferValueInMeters, data);
120
                        //Right
121
                        addOffsetedAndBufferedSegment(segments, line, offsetValueInMeters, bufferValueInMeters, data);
122
                        break;
123
                        
124
                    case CONTINUITY_MODE_CONT_DISC:
125
                        //Left
126
                        Geometry leftOffset;
127

    
128
                        if (line.isClosed() && line.getNumVertices() > 2 && line.isCCW()) {
129
                            Line cloned = line.cloneGeometry();
130
                            cloned.flip();
131
                            addOffsetedAndBufferedSegment(segments, cloned, offsetValueInMeters, bufferValueInMeters, data);
132
                        } else {
133
                            addOffsetedAndBufferedSegment(segments, line, -offsetValueInMeters, bufferValueInMeters, data);
134
                        }
135
                        //Right
136
                        splittedLine = splitLine(line, data.getSegmentsLength(), data.getHolesLength());
137
                        splittedSegments = splittedLine.getSegments();
138
                        splittedHoles = splittedLine.getHoles();
139
                        for (Line segment : splittedSegments) {
140
                            addOffsetedAndBufferedSegment(segments, segment, offsetValueInMeters, bufferValueInMeters, data);
141
                        }
142
                        for (Line hole : splittedHoles) {
143
                            addOffsetedAndBufferedSegment(holes, hole, offsetValueInMeters, bufferValueInMeters, data);
144
                        }
145
                        break;
146

    
147
                    case CONTINUITY_MODE_DISC_CONT:
148
                        //Left
149
                        splittedLine = splitLine(line, data.getSegmentsLength(), data.getHolesLength());
150
                        splittedSegments = splittedLine.getSegments();
151
                        splittedHoles = splittedLine.getHoles();
152
                        for (Line segment : splittedSegments) {
153
                            addOffsetedAndBufferedSegment(segments, segment, -offsetValueInMeters, bufferValueInMeters, data);
154
                        }
155
                        for (Line hole : splittedHoles) {
156
                            addOffsetedAndBufferedSegment(holes, hole, -offsetValueInMeters, bufferValueInMeters, data);
157
                        }
158
                        //Right
159
                        Geometry rightOffset;
160
                        if (line.isClosed() && line.getNumVertices() > 2 && line.isCCW()) {
161
                            Line cloned = line.cloneGeometry();
162
                            cloned.flip();
163
                            addOffsetedAndBufferedSegment(segments, cloned, -offsetValueInMeters, bufferValueInMeters, data);
164
                        } else {
165
                            addOffsetedAndBufferedSegment(segments, line, offsetValueInMeters, bufferValueInMeters, data);
166
                        }
167
                        break;
168

    
169
                        
170
                    case CONTINUITY_MODE_DISC_DISC:
171
                        splittedLine = splitLine(line, data.getSegmentsLength(), data.getHolesLength());
172
                        splittedSegments = splittedLine.getSegments();
173
                        splittedHoles = splittedLine.getHoles();
174
                        //Left
175
                        for (Line segment : splittedSegments) {
176
                            addOffsetedAndBufferedSegment(segments, segment, -offsetValueInMeters, bufferValueInMeters, data);
177
                        }
178
                        for (Line hole : splittedHoles) {
179
                            addOffsetedAndBufferedSegment(holes, hole, -offsetValueInMeters, bufferValueInMeters, data);
180
                        }
181
                        //Right
182
                        for (Line segment : splittedSegments) {
183
                            addOffsetedAndBufferedSegment(segments, segment, offsetValueInMeters, bufferValueInMeters, data);
184
                        }
185
                        for (Line hole : splittedHoles) {
186
                            addOffsetedAndBufferedSegment(holes, hole, offsetValueInMeters, bufferValueInMeters, data);
187
                        }
188
                        break;
189

    
190
                }
191

    
192
            }
193
            data.setSegmentsGeometry(segments);
194
            data.setHolesGeometry(holes);
195
        } catch (Exception ex) {
196
            LOGGER.warn("Can't calculate geometries.", ex);
197
//            Logger.getLogger(DefaultUrbanHorizontalSignageManager.class.getName()).log(Level.SEVERE, null, ex);
198
        }
199

    
200
    }
201

    
202
    protected void addOffsetedAndBufferedSegment(MultiPolygon segments, Line segment, final double offsetValueInMeters, final double bufferValueInMeters, UrbanHorizontalSignageData data) throws GeometryOperationException, GeometryOperationNotSupportedException {
203
        Geometry buffer;
204
        Geometry segmentOffset = segment.cloneGeometry().offset(offsetValueInMeters);
205
        if(segmentOffset == null){
206
            return;
207
        }
208
        buffer = segmentOffset.buffer(
209
                bufferValueInMeters,
210
                data.isRoundVertex() ? JOIN_STYLE_ROUND : JOIN_STYLE_MITRE,
211
                true
212
        );
213
        segments.addPrimitives(buffer);
214
    }
215

    
216
    /*
217
        segmentLength & holesLenght in meters
218
    */
219
    /*friend*/SplittedLine splitLine(Line line, double segmentLength, double holesLength) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException, CloneNotSupportedException {
220
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
221
        SplittedLine res = new SplittedLine();
222

    
223
        Point previousPoint = null;
224
        double previousLength = 0;
225
        Line currentSegment = geomManager.createLine(line.getGeometryType().getSubType());
226
        boolean isHole = false;
227
        boolean advanceToNext = true;
228
        Iterator<Point> it = line.iterator();
229
        Point currentPoint = null;
230
        while (it.hasNext() || !advanceToNext) {
231
            if (advanceToNext) {
232
                currentPoint = it.next();
233
            }
234
            if (previousPoint == null) {
235
                previousPoint = currentPoint.clone();
236
                currentSegment.addVertex(previousPoint);
237
                advanceToNext = true;
238
                continue;
239
            }
240
            double distance = previousPoint.distance(currentPoint);
241
            if (!isHole) {
242
                if (previousLength + distance < segmentLength) {
243
                    previousLength += distance;
244
                    if(distance > 0.0){
245
                        currentSegment.addVertex(currentPoint);
246
                    }
247
                    previousPoint = currentPoint.cloneGeometry();
248
                    advanceToNext = true;
249
                    continue;
250
                } else {
251
                    //buscar punto dentro del segmento a una distancia = segmentLengthMeters-previousLength
252
                    Point point = calculateIntermediatePoint(previousPoint, currentPoint, (segmentLength - previousLength) / distance);
253
                    //a?adirlo al currentSegment,
254
                    currentSegment.addVertex(point);
255
                    //a?adir  el currentSegment a la lista de segmentos
256
                    res.addSegment(currentSegment.cloneGeometry());
257
                    //crear un nuevo currentSegment y meter el punto como primero
258
                    currentSegment = geomManager.createLine(line.getGeometryType().getSubType());
259
                    currentSegment.addVertex(point);
260
                    //cambiar modo ==> isHole = true
261
                    isHole = !isHole;
262
                    previousPoint = point.clone();
263
                    previousLength = 0;
264
                    advanceToNext = false;
265
                    continue;
266
                }
267
            } else {
268
                if (previousLength + distance < holesLength) {
269
                    previousLength += distance;
270
                    if(distance > 0.0){
271
                        currentSegment.addVertex(currentPoint);
272
                    }
273
                    previousPoint = currentPoint.cloneGeometry();
274
                    advanceToNext = true;
275
                    continue;
276
                } else {
277
                    //buscar punto dentro del segmento a una distancia = segmentLengthMeters-previousLength
278
                    Point point = calculateIntermediatePoint(previousPoint, currentPoint, (holesLength - previousLength) / distance);
279
                    //a?adirlo al currentSegment,
280
                    currentSegment.addVertex(point);
281
                    //a?adir  el surrentSegment a la lista de segmentos
282
                    res.addHole(currentSegment.cloneGeometry());
283
                    //crear un nuevo currentSegment y meter el punto como primero
284
                    currentSegment = geomManager.createLine(line.getGeometryType().getSubType());
285
                    currentSegment.addVertex(point);
286
                    //Cambiar modo Segment <==> Hole
287
                    isHole = !isHole;
288
                    previousPoint = point.clone();
289
                    previousLength = 0;
290
                    advanceToNext = false;
291
                    continue;
292
                }
293
            }
294
        }
295
//        currentSegment.addVertex(currentPoint);
296
        if (currentSegment.getNumVertices() > 1) {
297
            if (isHole) {
298
                res.addHole(currentSegment.cloneGeometry());
299
            } else {
300
                res.addSegment(currentSegment.cloneGeometry());
301
            }
302
        }
303

    
304
        return res;
305
    }
306

    
307
    Point calculateIntermediatePoint(Point p1, Point p2, double lambda) throws CreateGeometryException, GeometryOperationNotSupportedException, GeometryOperationException {
308
        GeometryManager geomManager = GeometryLocator.getGeometryManager();
309
        GeometryType geomType = p1.getGeometryType();
310
        int subtype = geomType.getSubType();
311
        int dimension = geomType.getDimension();
312
        double[] coords = new double[dimension];
313
        Point p = geomManager.createPoint(0, 0, subtype);
314
        double distance = p1.distance(p2);
315
        for (int d = 0; d < dimension; d++) {
316
            p.setCoordinateAt(
317
                    d,
318
                    p1.getCoordinateAt(d) + (p2.getCoordinateAt(d) - p1.getCoordinateAt(d)) * lambda);
319
        }
320
        
321
        return p;
322
    }
323

    
324
    /*friend*/ static class SplittedLine {
325

    
326
        List<Line> segments;
327
        List<Line> holes;
328

    
329
        public SplittedLine() {
330
            segments = new ArrayList<>();
331
            holes = new ArrayList<>();
332
        }
333

    
334
        public List<Line> getSegments() {
335
            return this.segments;
336
        }
337

    
338
        public List<Line> getHoles() {
339
            return this.holes;
340
        }
341

    
342
        public void addSegment(Line segment) {
343
            this.segments.add(segment);
344
        }
345

    
346
        public void addHole(Line hole) {
347
            this.holes.add(hole);
348
        }
349

    
350
    }
351

    
352
}