1 package fr.ifremer.dali.ui.swing.util.map;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 import com.vividsolutions.jts.geom.LineString;
38 import com.vividsolutions.jts.geom.MultiLineString;
39 import com.vividsolutions.jts.geom.MultiPolygon;
40 import com.vividsolutions.jts.geom.Polygon;
41 import org.geotools.data.FileDataStore;
42 import org.geotools.data.FileDataStoreFinder;
43 import org.geotools.data.simple.SimpleFeatureCollection;
44 import org.geotools.data.simple.SimpleFeatureIterator;
45 import org.geotools.data.simple.SimpleFeatureSource;
46 import org.geotools.factory.CommonFactoryFinder;
47 import org.geotools.geometry.jts.ReferencedEnvelope;
48 import org.geotools.map.FeatureLayer;
49 import org.geotools.map.Layer;
50 import org.geotools.map.MapContent;
51 import org.geotools.styling.*;
52 import org.geotools.styling.Stroke;
53 import org.geotools.swing.JMapFrame;
54 import org.geotools.swing.data.JFileDataStoreChooser;
55 import org.geotools.swing.event.MapMouseEvent;
56 import org.geotools.swing.tool.CursorTool;
57 import org.opengis.feature.simple.SimpleFeature;
58 import org.opengis.feature.type.GeometryDescriptor;
59 import org.opengis.filter.Filter;
60 import org.opengis.filter.FilterFactory2;
61 import org.opengis.filter.identity.FeatureId;
62
63 import javax.swing.*;
64 import java.awt.*;
65 import java.awt.geom.AffineTransform;
66 import java.awt.geom.Rectangle2D;
67 import java.io.File;
68 import java.util.HashSet;
69 import java.util.Set;
70
71
72
73
74
75
76
77 public class SelectionLab {
78
79
80
81
82 private StyleFactory sf = CommonFactoryFinder.getStyleFactory();
83 private FilterFactory2 ff = CommonFactoryFinder.getFilterFactory2();
84
85
86
87
88 private enum GeomType { POINT, LINE, POLYGON }
89
90
91
92
93 private static final Color LINE_COLOUR = Color.BLUE;
94 private static final Color FILL_COLOUR = Color.CYAN;
95 private static final Color SELECTED_COLOUR = Color.YELLOW;
96 private static final float OPACITY = 1.0f;
97 private static final float LINE_WIDTH = 1.0f;
98 private static final float POINT_SIZE = 10.0f;
99
100 private JMapFrame mapFrame;
101 private SimpleFeatureSource featureSource;
102
103 private String geometryAttributeName;
104 private GeomType geometryType;
105
106
107
108
109 public static void main(String[] args) throws Exception {
110 SelectionLab me = new SelectionLab();
111
112 File file = JFileDataStoreChooser.showOpenFile("shp", null);
113 if (file == null) {
114 return;
115 }
116
117 me.displayShapefile(file);
118 }
119
120
121
122
123
124
125
126
127 public void displayShapefile(File file) throws Exception {
128 FileDataStore store = FileDataStoreFinder.getDataStore(file);
129 featureSource = store.getFeatureSource();
130 setGeometry();
131
132
133
134
135
136 MapContent map = new MapContent();
137 map.setTitle("Feature selection tool example");
138 Style style = createDefaultStyle();
139 Layer layer = new FeatureLayer(featureSource, style);
140 map.addLayer(layer);
141 mapFrame = new JMapFrame(map);
142 mapFrame.enableToolBar(true);
143 mapFrame.enableStatusBar(true);
144
145
146
147
148
149 JToolBar toolBar = mapFrame.getToolBar();
150 JButton btn = new JButton("Select");
151 toolBar.addSeparator();
152 toolBar.add(btn);
153
154
155
156
157
158
159
160
161
162 btn.addActionListener(e -> mapFrame.getMapPane().setCursorTool(
163 new CursorTool() {
164
165 @Override
166 public void onMouseClicked(MapMouseEvent ev) {
167 selectFeatures(ev);
168 }
169 }));
170
171
172
173
174
175 mapFrame.setSize(600, 600);
176 mapFrame.setVisible(true);
177 }
178
179
180
181
182
183
184
185
186
187 void selectFeatures(MapMouseEvent ev) {
188
189 System.out.println("Mouse click at: " + ev.getMapPosition());
190
191
192
193
194 Point screenPos = ev.getPoint();
195 Rectangle screenRect = new Rectangle(screenPos.x-2, screenPos.y-2, 5, 5);
196
197
198
199
200
201
202 AffineTransform screenToWorld = mapFrame.getMapPane().getScreenToWorldTransform();
203 Rectangle2D worldRect = screenToWorld.createTransformedShape(screenRect).getBounds2D();
204 ReferencedEnvelope bbox = new ReferencedEnvelope(
205 worldRect,
206 mapFrame.getMapContent().getCoordinateReferenceSystem());
207
208
209
210
211
212 Filter filter = ff.intersects(ff.property(geometryAttributeName), ff.literal(bbox));
213
214
215
216
217 try {
218 SimpleFeatureCollection selectedFeatures =
219 featureSource.getFeatures(filter);
220
221 Set<FeatureId> IDs = new HashSet<>();
222 try (SimpleFeatureIterator iter = selectedFeatures.features()) {
223 while (iter.hasNext()) {
224 SimpleFeature feature = iter.next();
225 IDs.add(feature.getIdentifier());
226
227 System.out.println(" " + feature.getIdentifier());
228 }
229
230 }
231
232 if (IDs.isEmpty()) {
233 System.out.println(" no feature selected");
234 }
235
236 displaySelectedFeatures(IDs);
237
238 } catch (Exception ex) {
239 ex.printStackTrace();
240 }
241 }
242
243
244
245
246
247
248
249
250
251 public void displaySelectedFeatures(Set<FeatureId> IDs) {
252 Style style;
253
254 if (IDs.isEmpty()) {
255 style = createDefaultStyle();
256
257 } else {
258 style = createSelectedStyle(IDs);
259 }
260
261 Layer layer = mapFrame.getMapContent().layers().get(0);
262 ((FeatureLayer) layer).setStyle(style);
263 mapFrame.getMapPane().repaint();
264 }
265
266
267
268
269
270
271 private Style createDefaultStyle() {
272 Rule rule = createRule(LINE_COLOUR, FILL_COLOUR);
273
274 FeatureTypeStyle fts = sf.createFeatureTypeStyle();
275 fts.rules().add(rule);
276
277 Style style = sf.createStyle();
278 style.featureTypeStyles().add(fts);
279 return style;
280 }
281
282
283
284
285
286
287
288 private Style createSelectedStyle(Set<FeatureId> IDs) {
289 Rule selectedRule = createRule(SELECTED_COLOUR, SELECTED_COLOUR);
290 selectedRule.setFilter(ff.id(IDs));
291
292 Rule otherRule = createRule(LINE_COLOUR, FILL_COLOUR);
293 otherRule.setElseFilter(true);
294
295 FeatureTypeStyle fts = sf.createFeatureTypeStyle();
296 fts.rules().add(selectedRule);
297 fts.rules().add(otherRule);
298
299 Style style = sf.createStyle();
300 style.featureTypeStyles().add(fts);
301 return style;
302 }
303
304
305
306
307
308
309
310
311 private Rule createRule(Color outlineColor, Color fillColor) {
312 Symbolizer symbolizer = null;
313 Fill fill = null;
314 Stroke stroke = sf.createStroke(ff.literal(outlineColor), ff.literal(LINE_WIDTH));
315
316 switch (geometryType) {
317 case POLYGON:
318 fill = sf.createFill(ff.literal(fillColor), ff.literal(OPACITY));
319 symbolizer = sf.createPolygonSymbolizer(stroke, fill, geometryAttributeName);
320 break;
321
322 case LINE:
323 symbolizer = sf.createLineSymbolizer(stroke, geometryAttributeName);
324 break;
325
326 case POINT:
327 fill = sf.createFill(ff.literal(fillColor), ff.literal(OPACITY));
328
329 Mark mark = sf.getCircleMark();
330 mark.setFill(fill);
331 mark.setStroke(stroke);
332
333 Graphic graphic = sf.createDefaultGraphic();
334 graphic.graphicalSymbols().clear();
335 graphic.graphicalSymbols().add(mark);
336 graphic.setSize(ff.literal(POINT_SIZE));
337
338 symbolizer = sf.createPointSymbolizer(graphic, geometryAttributeName);
339 }
340
341 Rule rule = sf.createRule();
342 rule.symbolizers().add(symbolizer);
343 return rule;
344 }
345
346
347
348
349
350
351 private void setGeometry() {
352 GeometryDescriptor geomDesc = featureSource.getSchema().getGeometryDescriptor();
353 geometryAttributeName = geomDesc.getLocalName();
354
355 Class<?> clazz = geomDesc.getType().getBinding();
356
357 if (Polygon.class.isAssignableFrom(clazz) ||
358 MultiPolygon.class.isAssignableFrom(clazz)) {
359 geometryType = GeomType.POLYGON;
360
361 } else if (LineString.class.isAssignableFrom(clazz) ||
362 MultiLineString.class.isAssignableFrom(clazz)) {
363
364 geometryType = GeomType.LINE;
365
366 } else {
367 geometryType = GeomType.POINT;
368 }
369
370 }
371
372
373 }