Changeset 11841 in josm for trunk/src/org/openstreetmap/josm/gui/layer/AbstractTileSourceLayer.java
- Timestamp:
- 2017-04-05T11:33:25+02:00 (7 years ago)
- File:
-
- 1 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;
Note:
See TracChangeset
for help on using the changeset viewer.