source: josm/trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java@ 4065

Last change on this file since 4065 was 4065, checked in by jttt, 13 years ago

Improved wms cache

  • files saved in original format (no need to recode to png)
  • possibility to tile with different pos/ppd that overlaps current tile
  • Property svn:eol-style set to native
File size: 9.5 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.layer;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5import static org.openstreetmap.josm.tools.I18n.trc;
6
7import java.awt.Color;
8import java.awt.Component;
9import java.awt.Font;
10import java.awt.Graphics;
11import java.awt.event.ActionEvent;
12import java.awt.image.BufferedImage;
13import java.awt.image.BufferedImageOp;
14import java.awt.image.ConvolveOp;
15import java.awt.image.Kernel;
16import java.util.List;
17
18import javax.swing.AbstractAction;
19import javax.swing.Icon;
20import javax.swing.JCheckBoxMenuItem;
21import javax.swing.JComponent;
22import javax.swing.JMenu;
23import javax.swing.JMenuItem;
24import javax.swing.JSeparator;
25import javax.swing.SwingUtilities;
26
27import org.openstreetmap.josm.Main;
28import org.openstreetmap.josm.actions.ImageryAdjustAction;
29import org.openstreetmap.josm.data.ProjectionBounds;
30import org.openstreetmap.josm.data.coor.EastNorth;
31import org.openstreetmap.josm.data.imagery.ImageryInfo;
32import org.openstreetmap.josm.data.imagery.ImageryInfo.ImageryType;
33import org.openstreetmap.josm.data.imagery.OffsetBookmark;
34import org.openstreetmap.josm.data.preferences.IntegerProperty;
35import org.openstreetmap.josm.io.imagery.OffsetServer;
36import org.openstreetmap.josm.io.imagery.OsmosnimkiOffsetServer;
37import org.openstreetmap.josm.tools.ImageProvider;
38
39public abstract class ImageryLayer extends Layer {
40 protected static final Icon icon = ImageProvider.get("imagery_small");
41
42 public static final IntegerProperty PROP_FADE_AMOUNT = new IntegerProperty("imagery.fade_amount", 0);
43 public static final IntegerProperty PROP_SHARPEN_LEVEL = new IntegerProperty("imagery.sharpen_level", 0);
44
45 public static Color getFadeColor() {
46 return Main.pref.getColor("imagery.fade", Color.white);
47 }
48
49 public static Color getFadeColorWithAlpha() {
50 Color c = getFadeColor();
51 return new Color(c.getRed(),c.getGreen(),c.getBlue(),PROP_FADE_AMOUNT.get()*255/100);
52 }
53
54 public static void setFadeColor(Color color) {
55 Main.pref.putColor("imagery.fade", color);
56 }
57
58 protected final ImageryInfo info;
59
60 protected double dx = 0.0;
61 protected double dy = 0.0;
62
63 protected int sharpenLevel;
64
65 protected boolean offsetServerSupported;
66 protected boolean offsetServerUsed;
67 protected OffsetServerThread offsetServerThread;
68
69 protected OffsetServerThread createoffsetServerThread() {
70 return new OffsetServerThread(new OsmosnimkiOffsetServer(
71 OsmosnimkiOffsetServer.PROP_SERVER_URL.get()));
72 }
73
74 public ImageryLayer(ImageryInfo info) {
75 super(info.getName());
76 this.info = info;
77 this.sharpenLevel = PROP_SHARPEN_LEVEL.get();
78 if (OffsetServer.PROP_SERVER_ENABLED.get()) {
79 offsetServerThread = createoffsetServerThread();
80 offsetServerThread.start();
81 }
82 }
83
84 public double getPPD(){
85 if (Main.map == null || Main.map.mapView == null) return Main.proj.getDefaultZoomInPPD();
86 ProjectionBounds bounds = Main.map.mapView.getProjectionBounds();
87 return Main.map.mapView.getWidth() / (bounds.maxEast - bounds.minEast);
88 }
89
90 public double getDx() {
91 return dx;
92 }
93
94 public double getDy() {
95 return dy;
96 }
97
98 public void setOffset(double dx, double dy) {
99 this.dx = dx;
100 this.dy = dy;
101 }
102
103 public void displace(double dx, double dy) {
104 setOffset(this.dx += dx, this.dy += dy);
105 }
106
107 public ImageryInfo getInfo() {
108 return info;
109 }
110
111 @Override
112 public Icon getIcon() {
113 return icon;
114 }
115
116 @Override
117 public boolean isMergable(Layer other) {
118 return false;
119 }
120
121 @Override
122 public void mergeFrom(Layer from) {
123 }
124
125 @Override
126 public Object getInfoComponent() {
127 return getToolTipText();
128 }
129
130 public static ImageryLayer create(ImageryInfo info) {
131 if (info.getImageryType() == ImageryType.WMS || info.getImageryType() == ImageryType.HTML)
132 return new WMSLayer(info);
133 else if (info.getImageryType() == ImageryType.TMS || info.getImageryType() == ImageryType.BING || info.getImageryType() == ImageryType.SCANEX)
134 return new TMSLayer(info);
135 else throw new AssertionError();
136 }
137
138 class ApplyOffsetAction extends AbstractAction {
139 private OffsetBookmark b;
140 ApplyOffsetAction(OffsetBookmark b) {
141 super(b.name);
142 this.b = b;
143 }
144
145 @Override
146 public void actionPerformed(ActionEvent ev) {
147 setOffset(b.dx, b.dy);
148 enableOffsetServer(false);
149 Main.main.menu.imageryMenu.refreshOffsetMenu();
150 Main.map.repaint();
151 }
152 }
153
154 public class OffsetAction extends AbstractAction implements LayerAction {
155 @Override
156 public void actionPerformed(ActionEvent e) {
157 }
158
159 @Override
160 public Component createMenuComponent() {
161 return getOffsetMenuItem();
162 }
163
164 @Override
165 public boolean supportLayers(List<Layer> layers) {
166 return false;
167 }
168 }
169
170 ImageryAdjustAction adjustAction = new ImageryAdjustAction(this);
171 AbstractAction useServerOffsetAction = new AbstractAction(tr("(use server offset)")) {
172 @Override
173 public void actionPerformed(ActionEvent e) {
174 enableOffsetServer(true);
175 }
176 };
177
178 public void enableOffsetServer(boolean enable) {
179 offsetServerUsed = enable;
180 if (offsetServerUsed && !offsetServerThread.isAlive()) {
181 offsetServerThread = createoffsetServerThread();
182 offsetServerThread.start();
183 }
184 }
185
186 public JMenuItem getOffsetMenuItem() {
187 JMenu subMenu = new JMenu(trc("layer", "Offset"));
188 subMenu.setIcon(ImageProvider.get("mapmode", "adjustimg"));
189 return (JMenuItem)getOffsetMenuItem(subMenu);
190 }
191
192 public JComponent getOffsetMenuItem(JComponent subMenu) {
193 JMenuItem adjustMenuItem = new JMenuItem(adjustAction);
194 if (OffsetBookmark.allBookmarks.isEmpty() && !offsetServerSupported) return adjustMenuItem;
195
196 subMenu.add(adjustMenuItem);
197 if (offsetServerSupported) {
198 JCheckBoxMenuItem item = new JCheckBoxMenuItem(useServerOffsetAction);
199 if (offsetServerUsed) {
200 item.setSelected(true);
201 }
202 subMenu.add(item);
203 }
204 subMenu.add(new JSeparator());
205 boolean hasBookmarks = false;
206 for (OffsetBookmark b : OffsetBookmark.allBookmarks) {
207 if (!b.isUsable(this)) {
208 continue;
209 }
210 JCheckBoxMenuItem item = new JCheckBoxMenuItem(new ApplyOffsetAction(b));
211 if (b.dx == dx && b.dy == dy && !offsetServerUsed) {
212 item.setSelected(true);
213 }
214 subMenu.add(item);
215 hasBookmarks = true;
216 }
217 return (hasBookmarks || offsetServerSupported) ? subMenu : adjustMenuItem;
218 }
219
220 public BufferedImage sharpenImage(BufferedImage img) {
221 if (sharpenLevel <= 0) return img;
222 int width = img.getWidth(null);
223 int height = img.getHeight(null);
224 BufferedImage tmp = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
225 tmp.getGraphics().drawImage(img, 0, 0, null);
226 Kernel kernel;
227 if (sharpenLevel == 1) {
228 kernel = new Kernel(3, 3, new float[] { -0.25f, -0.5f, -0.25f, -0.5f, 4, -0.5f, -0.25f, -0.5f, -0.25f});
229 } else {
230 kernel = new Kernel(3, 3, new float[] { -0.5f, -1, -0.5f, -1, 7, -1, -0.5f, -1, -0.5f});
231 }
232 BufferedImageOp op = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null);
233 return op.filter(tmp, null);
234 }
235
236 public void drawErrorTile(BufferedImage img) {
237 Graphics g = img.getGraphics();
238 g.setColor(Color.RED);
239 g.fillRect(0, 0, img.getWidth(), img.getHeight());
240 g.setFont(g.getFont().deriveFont(Font.PLAIN).deriveFont(36.0f));
241 g.setColor(Color.BLACK);
242
243 String text = tr("ERROR");
244 g.drawString(text, (img.getWidth() + g.getFontMetrics().stringWidth(text)) / 2, img.getHeight()/2);
245 }
246
247 protected class OffsetServerThread extends Thread {
248 OffsetServer offsetServer;
249 EastNorth oldCenter = new EastNorth(Double.NaN, Double.NaN);
250
251 public OffsetServerThread(OffsetServer offsetServer) {
252 this.offsetServer = offsetServer;
253 setDaemon(true);
254 }
255
256 private void updateOffset() {
257 if (Main.map == null || Main.map.mapView == null) return;
258 EastNorth center = Main.map.mapView.getCenter();
259 if (center.equals(oldCenter)) return;
260 oldCenter = center;
261
262 EastNorth offset = offsetServer.getOffset(getInfo(), center);
263 if (offset != null) {
264 setOffset(offset.east(),offset.north());
265 }
266 }
267
268 @Override
269 public void run() {
270 if (!offsetServerSupported) {
271 if (!offsetServer.isLayerSupported(info)) return;
272 offsetServerSupported = true;
273 }
274 offsetServerUsed = true;
275 SwingUtilities.invokeLater(new Runnable() {
276 @Override
277 public void run() {
278 Main.main.menu.imageryMenu.refreshOffsetMenu();
279 }
280 });
281 try {
282 while (offsetServerUsed) {
283 updateOffset();
284 Thread.sleep(1000);
285 }
286 } catch (InterruptedException e) {
287 }
288 offsetServerUsed = false;
289 }
290 }
291}
Note: See TracBrowser for help on using the repository browser.