Changeset 11841 in josm
- Timestamp:
- 2017-04-05T11:33:25+02:00 (8 years ago)
- Location:
- trunk/src/org/openstreetmap/josm/gui/layer
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
r11835 r11841 13 13 import java.awt.Image; 14 14 import java.awt.Point; 15 import java.awt.Shape; 15 16 import java.awt.Toolkit; 16 17 import java.awt.event.ActionEvent; 17 18 import java.awt.event.MouseAdapter; 18 19 import java.awt.event.MouseEvent; 20 import java.awt.geom.AffineTransform; 19 21 import java.awt.geom.Point2D; 20 22 import java.awt.geom.Rectangle2D; … … 25 27 import java.net.MalformedURLException; 26 28 import java.net.URL; 29 import java.text.MessageFormat; 27 30 import java.text.SimpleDateFormat; 28 31 import java.util.ArrayList; … … 62 65 import org.openstreetmap.gui.jmapviewer.OsmTileLoader; 63 66 import org.openstreetmap.gui.jmapviewer.Tile; 67 import org.openstreetmap.gui.jmapviewer.TileAnchor; 64 68 import org.openstreetmap.gui.jmapviewer.TileRange; 65 69 import org.openstreetmap.gui.jmapviewer.TileXY; … … 1044 1048 * @return the image of the tile or null. 1045 1049 */ 1046 private Image getLoadedTileImage(Tile tile) {1047 Image img = tile.getImage();1050 private BufferedImage getLoadedTileImage(Tile tile) { 1051 BufferedImage img = tile.getImage(); 1048 1052 if (!imageLoaded(img)) 1049 1053 return null; … … 1051 1055 } 1052 1056 1053 // 'source' is the pixel coordinates for the area that the img is capable of filling in. 1054 // However, we probably only want a portion of it. 1055 // 1056 // 'border' is the screen cordinates that need to be drawn. We must not draw outside of it. 1057 private void drawImageInside(Graphics g, Image sourceImg, Rectangle2D source, Rectangle2D border) { 1058 Rectangle2D target = source; 1059 1060 // If a border is specified, only draw the intersection if what we have combined with what we are supposed to draw. 1061 if (border != null) { 1062 target = source.createIntersection(border); 1063 if (Main.isDebugEnabled()) { 1064 Main.debug("source: " + source + "\nborder: " + border + "\nintersection: " + target); 1065 } 1066 } 1067 1068 // All of the rectangles are in screen coordinates. We need to how these correlate to the sourceImg pixels. 1069 // We could avoid doing this by scaling the image up to the 'source' size, but this should be cheaper. 1070 // 1071 // In some projections, x any y are scaled differently enough to 1072 // cause a pixel or two of fudge. Calculate them separately. 1073 double imageYScaling = sourceImg.getHeight(this) / source.getHeight(); 1074 double imageXScaling = sourceImg.getWidth(this) / source.getWidth(); 1075 1076 // How many pixels into the 'source' rectangle are we drawing? 1077 double screenXoffset = target.getX() - source.getX(); 1078 double screenYoffset = target.getY() - source.getY(); 1079 // And how many pixels into the image itself does that correlate to? 1080 int imgXoffset = (int) (screenXoffset * imageXScaling + 0.5); 1081 int imgYoffset = (int) (screenYoffset * imageYScaling + 0.5); 1082 // Now calculate the other corner of the image that we need 1083 // by scaling the 'target' rectangle's dimensions. 1084 int imgXend = imgXoffset + (int) (target.getWidth() * imageXScaling + 0.5); 1085 int imgYend = imgYoffset + (int) (target.getHeight() * imageYScaling + 0.5); 1086 1087 if (Main.isDebugEnabled()) { 1088 Main.debug("drawing image into target rect: " + target); 1089 } 1090 g.drawImage(sourceImg, 1091 (int) target.getX(), (int) target.getY(), 1092 (int) target.getMaxX(), (int) target.getMaxY(), 1093 imgXoffset, imgYoffset, 1094 imgXend, imgYend, 1095 this); 1096 } 1097 1098 private List<Tile> paintTileImages(Graphics g, TileSet ts) { 1057 /** 1058 * Draw a tile image on screen. 1059 * @param g the Graphics2D 1060 * @param toDrawImg tile image 1061 * @param anchorImage tile anchor in image coordinates 1062 * @param anchorScreen tile anchor in screen coordinates 1063 * @param clip clipping region in screen coordinates (can be null) 1064 */ 1065 private void drawImageInside(Graphics2D g, BufferedImage toDrawImg, TileAnchor anchorImage, TileAnchor anchorScreen, Shape clip) { 1066 AffineTransform imageToScreen = anchorImage.convert(anchorScreen); 1067 Point2D screen0 = imageToScreen.transform(new Point.Double(0, 0), null); 1068 Point2D screen1 = imageToScreen.transform(new Point.Double(toDrawImg.getWidth(), toDrawImg.getHeight()), null); 1069 Shape oldClip = null; 1070 if (clip != null) { 1071 oldClip = g.getClip(); 1072 g.clip(clip); 1073 } 1074 g.drawImage(toDrawImg, (int) Math.round(screen0.getX()), (int) Math.round(screen0.getY()), 1075 (int) Math.round(screen1.getX() - screen0.getX()), (int) Math.round(screen1.getY() - screen0.getY()), this); 1076 if (clip != null) { 1077 g.setClip(oldClip); 1078 } 1079 } 1080 1081 private List<Tile> paintTileImages(Graphics2D g, TileSet ts) { 1099 1082 Object paintMutex = new Object(); 1100 1083 List<TilePosition> missed = Collections.synchronizedList(new ArrayList<>()); 1101 1084 ts.visitTiles(tile -> { 1102 1085 boolean miss = false; 1103 Image img = null; 1086 BufferedImage img = null; 1087 TileAnchor anchorImage = null; 1104 1088 if (!tile.isLoaded() || tile.hasError()) { 1105 1089 miss = true; 1106 1090 } else { 1107 img = getLoadedTileImage(tile); 1091 synchronized (tile) { 1092 img = getLoadedTileImage(tile); 1093 anchorImage = tile.getAnchor(); 1094 } 1108 1095 if (img == null) { 1109 1096 miss = true; … … 1115 1102 } 1116 1103 img = applyImageProcessors((BufferedImage) img); 1117 Rectangle2D sourceRect = coordinateConverter.getRectangleForTile(tile);1104 TileAnchor anchorScreen = coordinateConverter.getScreenAnchorForTile(tile); 1118 1105 synchronized (paintMutex) { 1119 1106 //cannot paint in parallel 1120 drawImageInside(g, img, sourceRect, null);1107 drawImageInside(g, img, anchorImage, anchorScreen, null); 1121 1108 } 1122 1109 }, missed::add); … … 1132 1119 // It will not be from the zoom level that is being drawn currently. 1133 1120 // If drawing the displayZoomLevel, border is null and we draw the entire tile set. 1134 private List<Tile> paintTileImages(Graphics g, TileSet ts, int zoom, Tile border) {1121 private List<Tile> paintTileImages(Graphics2D g, TileSet ts, int zoom, Tile border) { 1135 1122 if (zoom <= 0) return Collections.emptyList(); 1136 Rectangle2D borderRect = coordinateConverter.getRectangleForTile(border);1123 Shape borderClip = coordinateConverter.getScreenQuadrilateralForTile(border); 1137 1124 List<Tile> missedTiles = new LinkedList<>(); 1138 1125 // The callers of this code *require* that we return any tiles that we do not draw in missedTiles. … … 1141 1128 for (Tile tile : ts.allTilesCreate()) { 1142 1129 boolean miss = false; 1143 Image img = null; 1130 BufferedImage img = null; 1131 TileAnchor anchorImage = null; 1144 1132 if (!tile.isLoaded() || tile.hasError()) { 1145 1133 miss = true; 1146 1134 } else { 1147 img = getLoadedTileImage(tile); 1135 synchronized (tile) { 1136 img = getLoadedTileImage(tile); 1137 anchorImage = tile.getAnchor(); 1138 } 1148 1139 if (img == null) { 1149 1140 miss = true; … … 1158 1149 img = applyImageProcessors((BufferedImage) img); 1159 1150 1160 Rectangle2D sourceRect = coordinateConverter.getRectangleForTile(tile); 1161 Rectangle2D clipRect; 1151 Shape clip; 1162 1152 if (tileSource.isInside(tile, border)) { 1163 clip Rect= null;1153 clip = null; 1164 1154 } else if (tileSource.isInside(border, tile)) { 1165 clip Rect = borderRect;1155 clip = borderClip; 1166 1156 } else { 1167 1157 continue; 1168 1158 } 1169 drawImageInside(g, img, sourceRect, clipRect); 1159 TileAnchor anchorScreen = coordinateConverter.getScreenAnchorForTile(tile); 1160 drawImageInside(g, img, anchorImage, anchorScreen, clip); 1170 1161 } 1171 1162 return missedTiles; -
trunk/src/org/openstreetmap/josm/gui/layer/imagery/TileCoordinateConverter.java
r11015 r11841 2 2 package org.openstreetmap.josm.gui.layer.imagery; 3 3 4 import java.awt.Shape; 5 import java.awt.geom.Path2D; 4 6 import java.awt.geom.Point2D; 5 7 import java.awt.geom.Rectangle2D; 6 8 7 9 import org.openstreetmap.gui.jmapviewer.Tile; 10 import org.openstreetmap.gui.jmapviewer.TileAnchor; 8 11 import org.openstreetmap.gui.jmapviewer.TileXY; 9 12 import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate; 13 import org.openstreetmap.gui.jmapviewer.interfaces.IProjected; 10 14 import org.openstreetmap.gui.jmapviewer.interfaces.TileSource; 15 import org.openstreetmap.josm.data.coor.EastNorth; 11 16 import org.openstreetmap.josm.data.coor.LatLon; 12 17 import org.openstreetmap.josm.data.projection.Projecting; … … 41 46 } 42 47 48 private MapViewPoint pos(IProjected p) { 49 return mapView.getState().getPointFor(new EastNorth(p)).add(settings.getDisplacement()); 50 } 51 43 52 /** 44 53 * Gets the projecting instance to use to convert between latlon and eastnorth coordinates. … … 51 60 /** 52 61 * Gets the top left position of the tile inside the map view. 62 * @param x x tile index 63 * @param y y tile index 64 * @param zoom zoom level 65 * @return the position 66 */ 67 public Point2D getPixelForTile(int x, int y, int zoom) { 68 ICoordinate coord = tileSource.tileXYToLatLon(x, y, zoom); 69 return pos(coord).getInView(); 70 } 71 72 /** 73 * Gets the top left position of the tile inside the map view. 53 74 * @param tile The tile 54 * @return The posit on.75 * @return The position. 55 76 */ 56 77 public Point2D getPixelForTile(Tile tile) { 57 ICoordinate coord = tile.getTileSource().tileXYToLatLon(tile); 58 return pos(coord).getInView(); 78 return this.getPixelForTile(tile.getXtile(), tile.getYtile(), tile.getZoom()); 59 79 } 60 80 … … 69 89 70 90 return pos(c1).rectTo(pos(c2)).getInView(); 91 } 92 93 /** 94 * Returns a quadrilateral formed by the 4 corners of the tile in screen coordinates. 95 * 96 * If the tile is rectangular, this will be the exact border of the tile. 97 * The tile may be more oddly shaped due to reprojection, then it is an approximation 98 * of the tile outline. 99 * @param tile the tile 100 * @return quadrilateral tile outline in screen coordinates 101 */ 102 public Shape getScreenQuadrilateralForTile(Tile tile) { 103 Point2D p00 = this.getPixelForTile(tile.getXtile(), tile.getYtile(), tile.getZoom()); 104 Point2D p10 = this.getPixelForTile(tile.getXtile() + 1, tile.getYtile(), tile.getZoom()); 105 Point2D p11 = this.getPixelForTile(tile.getXtile() + 1, tile.getYtile() + 1, tile.getZoom()); 106 Point2D p01 = this.getPixelForTile(tile.getXtile(), tile.getYtile() + 1, tile.getZoom()); 107 108 Path2D pth = new Path2D.Double(); 109 pth.moveTo(p00.getX(), p00.getY()); 110 pth.lineTo(p01.getX(), p01.getY()); 111 pth.lineTo(p11.getX(), p11.getY()); 112 pth.lineTo(p10.getX(), p10.getY()); 113 pth.closePath(); 114 return pth; 71 115 } 72 116 … … 87 131 return screenPixels/tilePixels; 88 132 } 133 134 /** 135 * Get {@link TileAnchor} for a tile in screen pixel coordinates. 136 * @param tile the tile 137 * @return position of the tile in screen coordinates 138 */ 139 public TileAnchor getScreenAnchorForTile(Tile tile) { 140 IProjected p1 = tileSource.tileXYtoProjected(tile.getXtile(), tile.getYtile(), tile.getZoom()); 141 IProjected p2 = tileSource.tileXYtoProjected(tile.getXtile() + 1, tile.getYtile() + 1, tile.getZoom()); 142 return new TileAnchor(pos(p1).getInView(), pos(p2).getInView()); 143 } 89 144 }
Note:
See TracChangeset
for help on using the changeset viewer.