Changeset 11431 in josm
- Timestamp:
- 2017-01-06T20:26:55+01:00 (8 years ago)
- Location:
- trunk
- Files:
-
- 5 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java
r11161 r11431 5 5 import static org.openstreetmap.josm.tools.I18n.tr; 6 6 7 import java.awt.AlphaComposite; 7 8 import java.awt.BasicStroke; 8 9 import java.awt.Color; 10 import java.awt.Composite; 9 11 import java.awt.Graphics2D; 12 import java.awt.LinearGradientPaint; 13 import java.awt.MultipleGradientPaint; 14 import java.awt.Paint; 10 15 import java.awt.Point; 16 import java.awt.Rectangle; 11 17 import java.awt.RenderingHints; 12 18 import java.awt.Stroke; 19 import java.awt.image.BufferedImage; 20 import java.awt.image.DataBufferInt; 21 import java.awt.image.Raster; 22 import java.io.BufferedReader; 23 import java.io.IOException; 13 24 import java.util.ArrayList; 14 25 import java.util.Arrays; … … 28 39 import org.openstreetmap.josm.data.preferences.ColorProperty; 29 40 import org.openstreetmap.josm.gui.MapView; 41 import org.openstreetmap.josm.io.CachedFile; 30 42 import org.openstreetmap.josm.tools.ColorScale; 43 import org.openstreetmap.josm.tools.JosmRuntimeException; 44 import org.openstreetmap.josm.tools.Utils; 31 45 32 46 /** … … 46 60 // draw lines between points belonging to different segments 47 61 private boolean forceLines; 62 // use alpha blending for line draw 63 private boolean alphaLines; 48 64 // draw direction arrows on the lines 49 65 private boolean direction; 66 /** width of line for paint **/ 67 private int lineWidth; 50 68 /** don't draw lines if longer than x meters **/ 51 private int lineWidth;52 69 private int maxLineLength; 70 // draw lines 53 71 private boolean lines; 54 72 /** paint large dots for points **/ … … 74 92 private ColorMode computeCacheColored; 75 93 private int computeCacheColorTracksTune; 94 private int computeCacheHeatMapDrawColorTableIdx; 76 95 77 96 //// Color-related fields … … 105 124 }; 106 125 126 /** heat map parameters **/ 127 128 // enabled or not (override by settings) 129 private boolean heatMapEnabled; 130 // draw small extra line 131 private boolean heatMapDrawExtraLine; 132 // used index for color table (parameter) 133 private int heatMapDrawColorTableIdx; 134 135 // normal buffered image and draw object (cached) 136 private BufferedImage heatMapImgGray; 137 private Graphics2D heatMapGraph2d; 138 139 // some cached values 140 Rectangle heatMapCacheScreenBounds = new Rectangle(); 141 int heatMapCacheVisibleSegments; 142 double heatMapCacheZoomScale; 143 int heatMapCacheLineWith; 144 145 // copied value for line drawing 146 private List<Integer> heatMapPolyX = new ArrayList<>(); 147 private List<Integer> heatMapPolyY = new ArrayList<>(); 148 149 // setup color maps used by heat map 150 private static Color[] heatMapLutColorJosmInferno = createColorFromResource("inferno"); 151 private static Color[] heatMapLutColorJosmViridis = createColorFromResource("viridis"); 152 private static Color[] heatMapLutColorJosmBrown2Green = createColorFromResource("brown2green"); 153 private static Color[] heatMapLutColorJosmRed2Blue = createColorFromResource("red2blue"); 154 155 // user defined heatmap color 156 private Color[] heatMapLutUserColor = createColorLut(Color.BLACK, Color.WHITE); 157 158 // heat map color in use 159 private Color[] heatMapLutColor; 160 107 161 private void setupColors() { 108 162 hdopAlpha = Main.pref.getInteger("hdop.color.alpha", -1); … … 112 166 dateScale = ColorScale.createHSBScale(256).addTitle(tr("Time")); 113 167 directionScale = ColorScale.createCyclicScale(256).setIntervalCount(4).addTitle(tr("Direction")); 168 heatMapLutColor = heatMapLutUserColor; 169 114 170 systemOfMeasurementChanged(null, null); 115 171 } … … 128 184 */ 129 185 public enum ColorMode { 130 NONE, VELOCITY, HDOP, DIRECTION, TIME; 186 NONE, VELOCITY, HDOP, DIRECTION, TIME, HEATMAP; 131 187 132 188 static ColorMode fromIndex(final int index) { … … 171 227 * Read coloring mode for specified layer from preferences 172 228 * @param layerName name of the GpxLayer 173 * @return colo ting mode229 * @return coloring mode 174 230 */ 175 231 public ColorMode getColorMode(String layerName) { … … 199 255 direction = Main.pref.getBoolean("draw.rawgps.direction", spec, false); 200 256 lineWidth = Main.pref.getInteger("draw.rawgps.linewidth", spec, 0); 257 alphaLines = Main.pref.getBoolean("draw.rawgps.lines.alpha-blend", spec, false); 201 258 202 259 if (!data.fromServer) { … … 220 277 largePointAlpha = Main.pref.getInteger("draw.rawgps.large.alpha", -1) & 0xFF; 221 278 279 // get heatmap parameters 280 heatMapEnabled = Main.pref.getBoolean("draw.rawgps.heatmap.enabled", spec, false); 281 heatMapDrawExtraLine = Main.pref.getBoolean("draw.rawgps.heatmap.line-extra", spec, false); 282 heatMapDrawColorTableIdx = Main.pref.getInteger("draw.rawgps.heatmap.colormap", specName(layerName), 0); 283 222 284 neutralColor = getColor(layerName, true); 223 285 velocityScale.setNoDataColor(neutralColor); … … 229 291 } 230 292 293 /** 294 * Draw all enabled GPX elements of layer. 295 * @param g the common draw object to use 296 * @param mv the meta data to current displayed area 297 * @param visibleSegments segments visible in the current scope of mv 298 */ 231 299 public void drawAll(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 300 301 final long timeStart = System.currentTimeMillis(); 232 302 233 303 checkCache(); … … 238 308 } 239 309 240 Stroke storedStroke = g.getStroke(); 241 310 fixColors(visibleSegments); 311 312 // backup the environment 313 Composite oldComposite = g.getComposite(); 314 Stroke oldStroke = g.getStroke(); 315 Paint oldPaint = g.getPaint(); 316 317 // set hints for the render 242 318 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, 243 319 Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false) ? … … 247 323 g.setStroke(new BasicStroke(lineWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 248 324 } 249 fixColors(visibleSegments); 250 drawLines(g, mv, visibleSegments); 325 326 // global enabled or select via color 327 boolean useHeatMap = heatMapEnabled || ColorMode.HEATMAP == colored; 328 329 // default global alpha level 330 float layerAlpha = 1.00f; 331 332 // extract current alpha blending value 333 if (oldComposite instanceof AlphaComposite) { 334 layerAlpha = ((AlphaComposite) oldComposite).getAlpha(); 335 } 336 337 // use heatmap background layer 338 if (useHeatMap) { 339 drawHeatMap(g, mv, visibleSegments); 340 } else { 341 // use normal line style or alpha-blending lines 342 if (!alphaLines) { 343 drawLines(g, mv, visibleSegments); 344 } else { 345 drawLinesAlpha(g, mv, visibleSegments, layerAlpha); 346 } 347 } 348 349 // override global alpha settings (smooth overlay) 350 if (alphaLines || useHeatMap) { 351 g.setComposite(AlphaComposite.SrcOver.derive(0.25f * layerAlpha)); 352 } 353 354 // normal overlays 251 355 drawArrows(g, mv, visibleSegments); 252 356 drawPoints(g, mv, visibleSegments); 253 if (lineWidth != 0) { 254 g.setStroke(storedStroke); 255 } 256 } 257 357 358 // restore environment 359 g.setPaint(oldPaint); 360 g.setStroke(oldStroke); 361 g.setComposite(oldComposite); 362 363 // show some debug info 364 if (Main.isDebugEnabled() && !visibleSegments.isEmpty()) { 365 final long timeDiff = System.currentTimeMillis() - timeStart; 366 367 Main.debug("gpxdraw::draw takes " + 368 Utils.getDurationString(timeDiff) + 369 "(" + 370 "segments= " + visibleSegments.size() + 371 ", per 10000 = " + Utils.getDurationString(10000 * timeDiff / visibleSegments.size()) + 372 ")" 373 ); 374 } 375 } 376 377 /** 378 * Calculate colors of way segments based on latest configuration settings 379 */ 258 380 public void calculateColors() { 259 381 double minval = +1e10; … … 392 514 } 393 515 516 // heat mode 517 if (ColorMode.HEATMAP == colored && neutralColor != null) { 518 519 // generate new user color map 520 heatMapLutUserColor = createColorLut(Color.BLACK, neutralColor.darker(), 521 neutralColor, neutralColor.brighter(), Color.WHITE); 522 523 // decide what, keep order is sync with setting on GUI 524 Color[][] lut = { 525 heatMapLutUserColor, 526 heatMapLutColorJosmInferno, 527 heatMapLutColorJosmViridis, 528 heatMapLutColorJosmBrown2Green, 529 heatMapLutColorJosmRed2Blue 530 }; 531 532 // select by index 533 if (heatMapDrawColorTableIdx < lut.length) { 534 heatMapLutColor = lut[ heatMapDrawColorTableIdx ]; 535 } else { 536 // fallback 537 heatMapLutColor = heatMapLutUserColor; 538 } 539 540 // force redraw of image 541 heatMapCacheVisibleSegments = 0; 542 } 543 394 544 computeCacheInSync = true; 395 545 } 396 546 547 /** 548 * Draw all GPX ways segments 549 * @param g the common draw object to use 550 * @param mv the meta data to current displayed area 551 * @param visibleSegments segments visible in the current scope of mv 552 */ 397 553 private void drawLines(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 398 554 if (lines) { … … 414 570 } 415 571 572 /** 573 * Draw all GPX arrays 574 * @param g the common draw object to use 575 * @param mv the meta data to current displayed area 576 * @param visibleSegments segments visible in the current scope of mv 577 */ 416 578 private void drawArrows(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 417 579 /**************************************************************** … … 475 637 } 476 638 639 /** 640 * Draw all GPX points 641 * @param g the common draw object to use 642 * @param mv the meta data to current displayed area 643 * @param visibleSegments segments visible in the current scope of mv 644 */ 477 645 private void drawPoints(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 478 646 /**************************************************************** … … 551 719 } 552 720 721 /** 722 * Draw GPX lines by using alpha blending 723 * @param g the common draw object to use 724 * @param mv the meta data to current displayed area 725 * @param visibleSegments segments visible in the current scope of mv 726 * @param layerAlpha the color alpha value set for that operation 727 */ 728 private void drawLinesAlpha(Graphics2D g, MapView mv, List<WayPoint> visibleSegments, float layerAlpha) { 729 730 // 1st. backup the paint environment ---------------------------------- 731 Composite oldComposite = g.getComposite(); 732 Stroke oldStroke = g.getStroke(); 733 Paint oldPaint = g.getPaint(); 734 735 // 2nd. determine current scale factors ------------------------------- 736 737 // adjust global settings 738 final int globalLineWidth = Math.min(Math.max(lineWidth, 1), 20); 739 740 // cache scale of view 741 final double zoomScale = mv.getScale(); 742 743 // 3rd. determine current paint parameters ----------------------------- 744 745 // alpha value is based on zoom and line with combined with global layer alpha 746 float theLineAlpha = Math.min(Math.max((0.50f/(float) zoomScale)/(globalLineWidth + 1), 0.001f), 0.50f) * layerAlpha; 747 final int theLineWith = (int) (lineWidth / zoomScale) + 1; 748 749 // 4th setup virtual paint area ---------------------------------------- 750 751 // set line format and alpha channel for all overlays (more lines -> few overlap -> more transparency) 752 g.setStroke(new BasicStroke(theLineWith, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 753 g.setComposite(AlphaComposite.SrcOver.derive(theLineAlpha)); 754 755 // last used / calculated entries 756 Point lastPaintPnt = null; 757 758 // 5th draw the layer --------------------------------------------------- 759 760 // for all points 761 for (WayPoint trkPnt : visibleSegments) { 762 763 // transform coordinates 764 final Point paintPnt = mv.getPoint(trkPnt.getEastNorth()); 765 766 // skip single points 767 if (lastPaintPnt != null && trkPnt.drawLine && !lastPaintPnt.equals(paintPnt)) { 768 769 // set different color 770 g.setColor(trkPnt.customColoring); 771 772 // draw it 773 g.drawLine(lastPaintPnt.x, lastPaintPnt.y, paintPnt.x, paintPnt.y); 774 } 775 776 lastPaintPnt = paintPnt; 777 } 778 779 // @last restore modified paint environment ----------------------------- 780 g.setPaint(oldPaint); 781 g.setStroke(oldStroke); 782 g.setComposite(oldComposite); 783 } 784 785 /** 786 * Creates a linear distributed colormap by linear blending between colors 787 * @param colors 1..n colors 788 * @return array of Color objects 789 */ 790 protected static Color[] createColorLut(Color... colors) { 791 792 // number of lookup entries 793 int tableSize = 256; 794 795 // create image an paint object 796 BufferedImage img = new BufferedImage(tableSize, 1, BufferedImage.TYPE_INT_RGB); 797 Graphics2D g = img.createGraphics(); 798 799 float[] fract = new float[ colors.length ]; 800 801 // distribute fractions (define position of color in map) 802 for (int i = 0; i < colors.length; ++i) { 803 fract[i] = i * (1.0f / colors.length); 804 } 805 806 // draw the gradient map 807 LinearGradientPaint gradient = new LinearGradientPaint(0, 0, tableSize, 1, fract, colors, 808 MultipleGradientPaint.CycleMethod.NO_CYCLE); 809 g.setPaint(gradient); 810 g.fillRect(0, 0, tableSize, 1); 811 g.dispose(); 812 813 // access it via raw interface 814 final Raster imgRaster = img.getData(); 815 816 // the pixel storage 817 int[] pixel = new int[1]; 818 819 Color[] colorTable = new Color[tableSize]; 820 821 // map the range 0..255 to 0..pi/2 822 final double mapTo90Deg = Math.PI / 2.0 / 255.0; 823 824 // create the lookup table 825 for (int i = 0; i < tableSize; i++) { 826 827 // get next single pixel 828 imgRaster.getDataElements((int) (i * (double) img.getWidth() / tableSize), 0, pixel); 829 830 // get color and map 831 Color c = new Color(pixel[0]); 832 833 // smooth alpha like sin curve 834 int alpha = (int) (Math.sin(i * mapTo90Deg) * 255); 835 836 // alpha with pre-offset, first color -> full transparent 837 alpha = i > 0 ? (75 + alpha) : 0; 838 839 // shrink to maximum bound 840 if (alpha > 255) { 841 alpha = 255; 842 } 843 844 // increase transparency for higher values ( avoid big saturation ) 845 if (i > 240 && 255 == alpha) { 846 alpha -= (i - 240); 847 } 848 849 // fill entry in table, assign a alpha value 850 colorTable[i] = new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha); 851 } 852 853 // transform into lookup table 854 return colorTable; 855 } 856 857 /** 858 * Creates a colormap by using a static color map with 1..n colors (RGB 0.0 ..1.0) 859 * @param data array of multiple RGB color [n][3] 860 * @return a dynamic list of color objects 861 */ 862 protected static Color[] createColorFromRawArray(double[][] data) { 863 864 // create the array 865 Color[] color = new Color[ data.length ]; 866 867 for (int k = 0; k < data.length; k++) { 868 // cast an map to linear array 869 color[k] = new Color((float) data[k][0], (float) data[k][1], (float) data[k][2]); 870 } 871 872 // forward 873 return createColorLut(color); 874 } 875 876 /** 877 * Creates a colormap by using a static color map with 1..n colors (RGB 0.0 ..1.0) 878 * @param str the filename (without extension) to look for into data/gpx 879 * @return the parsed colormap 880 */ 881 protected static Color[] createColorFromResource(String str) { 882 883 // create resource string 884 final String colorFile = "resource://data/gpx/" + str + ".txt"; 885 886 List<Color> colorList = new ArrayList<>(); 887 888 // try to load the file 889 try (CachedFile cf = new CachedFile(colorFile); BufferedReader br = cf.getContentReader()) { 890 891 String line; 892 893 // process lines 894 while ((line = br.readLine()) != null) { 895 896 // use comma as separator 897 String[] column = line.split(","); 898 899 // empty or comment line 900 if (column.length < 3 || column[0].startsWith("#")) { 901 continue; 902 } 903 904 // extract RGB value 905 float r = Float.parseFloat(column[0]); 906 float g = Float.parseFloat(column[1]); 907 float b = Float.parseFloat(column[2]); 908 909 // some color tables are 0..1.0 and some 0.255 910 float scale = (r < 1 && g < 1 && b < 1) ? 1 : 255; 911 912 colorList.add(new Color(r/scale, g/scale, b/scale)); 913 } 914 } catch (IOException e) { 915 throw new JosmRuntimeException(e); 916 } 917 918 // fallback if empty or failed 919 if (colorList.isEmpty()) { 920 colorList.add(Color.BLACK); 921 colorList.add(Color.WHITE); 922 } 923 924 return createColorLut(colorList.toArray(new Color[ colorList.size() ])); 925 } 926 927 /** 928 * Draw gray heat map with current Graphics2D setting 929 * @param gB the common draw object to use 930 * @param mv the meta data to current displayed area 931 * @param listSegm segments visible in the current scope of mv 932 * @param foreComp composite use to draw foreground objects 933 * @param foreStroke stroke use to draw foreground objects 934 * @param backComp composite use to draw background objects 935 * @param backStroke stroke use to draw background objects 936 */ 937 private void drawHeatGrayMap(Graphics2D gB, MapView mv, List<WayPoint> listSegm, 938 Composite foreComp, Stroke foreStroke, 939 Composite backComp, Stroke backStroke) { 940 941 // draw foreground 942 boolean drawForeground = foreComp != null && foreStroke != null; 943 944 // set initial values 945 gB.setStroke(backStroke); gB.setComposite(backComp); 946 947 // for all points, draw single lines by using optimize drawing 948 for (WayPoint trkPnt : listSegm) { 949 950 // something to paint or color changed (new segment needed, decrease performance ;-() 951 if (!trkPnt.drawLine && !heatMapPolyX.isEmpty()) { 952 953 // convert to primitive type 954 final int[] polyXArr = heatMapPolyX.stream().mapToInt(Integer::intValue).toArray(); 955 final int[] polyYArr = heatMapPolyY.stream().mapToInt(Integer::intValue).toArray(); 956 957 // a.) draw background 958 gB.drawPolyline(polyXArr, polyYArr, polyXArr.length); 959 960 // b.) draw extra foreground 961 if (drawForeground && heatMapDrawExtraLine) { 962 963 gB.setStroke(foreStroke); gB.setComposite(foreComp); 964 gB.drawPolyline(polyXArr, polyYArr, polyXArr.length); 965 gB.setStroke(backStroke); gB.setComposite(backComp); 966 } 967 968 // drop used pints 969 heatMapPolyX.clear(); heatMapPolyY.clear(); 970 971 } else { 972 973 // get transformed coordinates 974 final Point paintPnt = mv.getPoint(trkPnt.getEastNorth()); 975 976 // store only the integer part (make sense because pixel is 1:1 here) 977 heatMapPolyX.add((int) paintPnt.getX()); 978 heatMapPolyY.add((int) paintPnt.getY()); 979 } 980 } 981 } 982 983 /** 984 * Map the gray map to heat map and draw them with current Graphics2D setting 985 * @param g the common draw object to use 986 * @param imgGray gray scale input image 987 * @param sampleRaster the line with for drawing 988 */ 989 private void drawHeatMapGrayMap(Graphics2D g, BufferedImage imgGray, int sampleRaster) { 990 991 final int[] imgPixels = ((DataBufferInt) imgGray.getRaster().getDataBuffer()).getData(); 992 993 // samples offset and bounds are scaled with line width derived from zoom level 994 final int offX = Math.max(1, sampleRaster / 2); 995 final int offY = Math.max(1, sampleRaster / 2); 996 997 final int maxPixelX = imgGray.getWidth(); 998 final int maxPixelY = imgGray.getHeight(); 999 1000 int lastPixelY = 0; 1001 int lastPixelColor = 0; 1002 1003 // resample gray scale image with line linear weight of next sample in line 1004 // process each line and draw pixels / rectangles with same color with one operations 1005 for (int x = 0; x < maxPixelX; x += offX) { 1006 for (int y = 0; y < maxPixelY; y += offY) { 1007 1008 int thePixelColor = 0; 1009 1010 // sample the image (it is gray scale) 1011 int offset = (x * maxPixelX) + y; 1012 1013 // merge next pixels of window of line 1014 for (int k = 0; k < offX && offset + k < imgPixels.length; k++) { 1015 thePixelColor += imgPixels[offset+k] & 0xFF; 1016 } 1017 1018 // mean value 1019 thePixelColor /= offX; 1020 1021 // restart -> use initial sample 1022 if (0 == y) { 1023 lastPixelY = 0; lastPixelColor = thePixelColor; 1024 } 1025 1026 // different color to last one ? 1027 if (Math.abs(lastPixelColor - thePixelColor) > 1) { 1028 1029 // draw only foreground pixels, skip small variations 1030 if (lastPixelColor > 1+1) { 1031 1032 // gray to RGB mapping 1033 g.setColor(heatMapLutColor[ lastPixelColor ]); 1034 1035 // start point for draw ( 1036 int yN = lastPixelY > 0 ? lastPixelY : y; 1037 1038 // box from from last Y pixel to current pixel 1039 if (offX < sampleRaster) { 1040 g.fillRect(yN, x, offY + y - yN, offX); 1041 } else { 1042 g.drawRect(yN, x, offY + y - yN, offX); 1043 } 1044 } 1045 // restart detection 1046 lastPixelY = y; lastPixelColor = thePixelColor; 1047 } 1048 } 1049 } 1050 } 1051 1052 /** 1053 * Collect and draw GPS segments and displays a heat-map 1054 * @param g the common draw object to use 1055 * @param mv the meta data to current displayed area 1056 * @param visibleSegments segments visible in the current scope of mv 1057 */ 1058 private void drawHeatMap(Graphics2D g, MapView mv, List<WayPoint> visibleSegments) { 1059 1060 // get bounds of screen image and projection, zoom and adjust input parameters 1061 final Rectangle screenBounds = g.getDeviceConfiguration().getBounds(); 1062 final double zoomScale = mv.getScale(); 1063 1064 // adjust global settings 1065 final int globalLineWidth = Math.min(Math.max(lineWidth, 1), 20); 1066 1067 // 1st setup virtual paint area ---------------------------------------- 1068 1069 // HACK: sometime screen bounds does not return valid values when picture is shifted 1070 // therefore we use a bigger area to avoid missing parts of image 1071 screenBounds.width = screenBounds.width * 3 / 2; 1072 screenBounds.height = screenBounds.height * 3 / 2; 1073 1074 // new image buffer needed 1075 final boolean imageSetup = null == heatMapImgGray || !heatMapCacheScreenBounds.equals(screenBounds); 1076 1077 // screen bounds changed, need new image buffer ? 1078 if (imageSetup) { 1079 // we would use a "pure" grayscale image, but there is not efficient way to map gray scale values to RGB) 1080 heatMapImgGray = new BufferedImage(screenBounds.width, screenBounds.height, BufferedImage.TYPE_INT_ARGB); 1081 heatMapGraph2d = heatMapImgGray.createGraphics(); 1082 heatMapGraph2d.setBackground(new Color(0, 0, 0, 255)); 1083 heatMapGraph2d.setColor(Color.WHITE); 1084 1085 // cache it 1086 heatMapCacheScreenBounds = screenBounds; 1087 } 1088 1089 // 2nd. determine current scale factors ------------------------------- 1090 1091 // the line width (foreground: draw extra small footprint line of track) 1092 final int lineWidthB = Math.max((int) (globalLineWidth / zoomScale) + 1, 2); 1093 final int lineWidthF = lineWidthB > 2 ? (globalLineWidth - 1) : 0; 1094 1095 // recalculation of image needed 1096 final boolean imageRecalc = heatMapCacheVisibleSegments != visibleSegments.size() || 1097 heatMapCacheZoomScale != zoomScale || 1098 heatMapCacheLineWith != globalLineWidth; 1099 1100 // 3rd Calculate the heat map data by draw GPX traces with alpha value ---------- 1101 1102 // need re-generation of gray image ? 1103 if (imageSetup || imageRecalc) { 1104 1105 // clear background 1106 heatMapGraph2d.clearRect(0, 0, heatMapImgGray.getWidth(), heatMapImgGray.getHeight()); 1107 1108 // alpha combines both values, therefore the foreground shall be lighter 1109 final float lineAlphaB = Math.min(Math.max((0.40f/(float) zoomScale)/(globalLineWidth + 1), 0.001f), 0.50f); 1110 final float lineAlphaF = lineAlphaB / 1.5f; 1111 1112 // derive draw parameters and draw 1113 drawHeatGrayMap(heatMapGraph2d, mv, visibleSegments, 1114 lineWidthF > 1 ? AlphaComposite.SrcOver.derive(lineAlphaF) : null, 1115 new BasicStroke(lineWidthF, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND), 1116 AlphaComposite.SrcOver.derive(lineAlphaB), 1117 new BasicStroke(lineWidthB, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); 1118 1119 // remember draw parameters 1120 heatMapCacheVisibleSegments = visibleSegments.size(); 1121 heatMapCacheZoomScale = zoomScale; 1122 heatMapCacheLineWith = lineWidth; 1123 } 1124 1125 // 4th. Draw data on target layer, map data via color lookup table -------------- 1126 drawHeatMapGrayMap(g, heatMapImgGray, lineWidthB); 1127 } 1128 1129 /** 1130 * Apply default color configuration to way segments 1131 * @param visibleSegments segments visible in the current scope of mv 1132 */ 553 1133 private void fixColors(List<WayPoint> visibleSegments) { 554 1134 for (WayPoint trkPnt : visibleSegments) { … … 565 1145 if ((computeCacheMaxLineLengthUsed != maxLineLength) || (!neutralColor.equals(computeCacheColorUsed)) 566 1146 || (computeCacheColored != colored) || (computeCacheColorTracksTune != colorTracksTune) 567 || (computeCacheColorDynamic != colorModeDynamic)) { 1147 || (computeCacheColorDynamic != colorModeDynamic) 1148 || (computeCacheHeatMapDrawColorTableIdx != heatMapDrawColorTableIdx) 1149 ) { 568 1150 computeCacheMaxLineLengthUsed = maxLineLength; 569 1151 computeCacheInSync = false; … … 572 1154 computeCacheColorTracksTune = colorTracksTune; 573 1155 computeCacheColorDynamic = colorModeDynamic; 574 } 575 } 576 1156 computeCacheHeatMapDrawColorTableIdx = heatMapDrawColorTableIdx; 1157 } 1158 } 1159 1160 /** 1161 * callback when data is changed, invalidate cached configuration parameters 1162 */ 577 1163 public void dataChanged() { 578 1164 computeCacheInSync = false; 579 1165 } 580 1166 1167 /** 1168 * Draw all GPX arrays 1169 * @param g the common draw object to use 1170 * @param mv the meta data to current displayed area 1171 */ 581 1172 public void drawColorBar(Graphics2D g, MapView mv) { 582 1173 int w = mv.getWidth(); 1174 1175 // set do default 1176 g.setComposite(AlphaComposite.SrcOver.derive(1.00f)); 1177 583 1178 if (colored == ColorMode.HDOP) { 584 1179 hdopScale.drawColorBar(g, w-30, 50, 20, 100, 1.0); -
trunk/src/org/openstreetmap/josm/gui/preferences/display/GPXSettingsPanel.java
r11039 r11431 56 56 private final JRadioButton colorTypeDilution = new JRadioButton(tr("Dilution of Position (red = high, green = low, if available)")); 57 57 private final JRadioButton colorTypeTime = new JRadioButton(tr("Track date")); 58 private final JRadioButton colorTypeHeatMap = new JRadioButton(tr("Heat Map (dark = few tracks, bright = many tracks)")); 58 59 private final JRadioButton colorTypeNone = new JRadioButton(tr("Single Color (can be customized for named layers)")); 59 60 private final JRadioButton colorTypeGlobal = new JRadioButton(tr("Use global settings")); 60 61 private final JosmComboBox<String> colorTypeVelocityTune = new JosmComboBox<>(new String[] {tr("Car"), tr("Bicycle"), tr("Foot")}); 62 private final JosmComboBox<String> colorTypeHeatMapTune = new JosmComboBox<>(new String[] {tr("User"), tr("Inferno"), tr("Viridis"), 63 tr("Wood"), tr("Heat")}); 61 64 private final JCheckBox makeAutoMarkers = new JCheckBox(tr("Create markers when reading GPX")); 62 65 private final JCheckBox drawGpsArrows = new JCheckBox(tr("Draw Direction Arrows")); … … 69 72 private final JosmTextField audioWaypointLabelPattern = new JosmTextField(); 70 73 private final JCheckBox useGpsAntialiasing = new JCheckBox(tr("Smooth GPX graphics (antialiasing)")); 74 private final JCheckBox drawLineWithAlpha = new JCheckBox(tr("Draw with Opacity (alpha blending) ")); 71 75 72 76 private String layerName; … … 180 184 }); 181 185 drawGpsArrows.setToolTipText(tr("Draw direction arrows for lines, connecting GPS points.")); 182 add(drawGpsArrows, GBC.eop().insets( 40, 0, 0, 0));186 add(drawGpsArrows, GBC.eop().insets(20, 0, 0, 0)); 183 187 184 188 // drawGpsArrowsFast 185 189 drawGpsArrowsFast.setToolTipText(tr("Draw the direction arrows using table lookups instead of complex math.")); 186 add(drawGpsArrowsFast, GBC.eop().insets( 60, 0, 0, 0));190 add(drawGpsArrowsFast, GBC.eop().insets(40, 0, 0, 0)); 187 191 ExpertToggleAction.addVisibilitySwitcher(drawGpsArrowsFast); 188 192 189 193 // drawGpsArrowsMinDist 190 194 drawGpsArrowsMinDist.setToolTipText(tr("Do not draw arrows if they are not at least this distance away from the last one.")); 191 add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets( 60, 0, 0, 0));195 add(new JLabel(tr("Minimum distance (pixels)")), GBC.std().insets(40, 0, 0, 0)); 192 196 add(drawGpsArrowsMinDist, GBC.eol().fill(GBC.HORIZONTAL).insets(5, 0, 0, 5)); 193 197 … … 210 214 add(useGpsAntialiasing, GBC.eop().insets(20, 0, 0, 0)); 211 215 ExpertToggleAction.addVisibilitySwitcher(useGpsAntialiasing); 216 217 // alpha blending 218 drawLineWithAlpha.setToolTipText(tr("Apply dynamic alpha-blending and adjust width based on zoom level for all GPX lines.")); 219 add(drawLineWithAlpha, GBC.eop().insets(20, 0, 0, 0)); 220 ExpertToggleAction.addVisibilitySwitcher(drawLineWithAlpha); 212 221 213 222 // colorTracks … … 221 230 colorGroup.add(colorTypeDilution); 222 231 colorGroup.add(colorTypeTime); 232 colorGroup.add(colorTypeHeatMap); 223 233 224 234 colorTypeVelocity.addChangeListener(e -> { … … 226 236 colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected()); 227 237 }); 238 239 colorTypeHeatMap.addChangeListener(e -> { 240 colorTypeHeatMapTune.setEnabled(colorTypeHeatMap.isSelected()); 241 colorDynamic.setEnabled(false); 242 }); 243 228 244 colorTypeDilution.addChangeListener(e -> colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected())); 229 245 … … 234 250 tr("Colors points and track segments by dilution of position (HDOP). Your capture device needs to log that information.")); 235 251 colorTypeTime.setToolTipText(tr("Colors points and track segments by its timestamp.")); 252 colorTypeHeatMap.setToolTipText(tr("Collected points and track segments for a position and displayed as heat map.")); 236 253 237 254 // color Tracks by Velocity Tune 238 255 colorTypeVelocityTune.setToolTipText(tr("Allows to tune the track coloring for different average speeds.")); 256 257 colorTypeHeatMapTune.setToolTipText(tr("Selects the color schema for heat map.")); 239 258 240 259 add(Box.createVerticalGlue(), GBC.eol().insets(0, 20, 0, 0)); … … 250 269 add(colorTypeDilution, GBC.eol().insets(40, 0, 0, 0)); 251 270 add(colorTypeTime, GBC.eol().insets(40, 0, 0, 0)); 271 add(colorTypeHeatMap, GBC.std().insets(40, 0, 0, 0)); 272 add(colorTypeHeatMapTune, GBC.eop().insets(5, 0, 0, 5)); 273 252 274 ExpertToggleAction.addVisibilitySwitcher(colorTypeDirection); 253 275 ExpertToggleAction.addVisibilitySwitcher(colorTypeDilution); … … 316 338 drawRawGpsMaxLineLength.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.max-line-length", layerName, 200))); 317 339 drawLineWidth.setText(Integer.toString(Main.pref.getInteger("draw.rawgps.linewidth", layerName, 0))); 340 drawLineWithAlpha.setSelected(Main.pref.getBoolean("draw.rawgps.lines.alpha-blend", layerName, false)); 318 341 forceRawGpsLines.setSelected(Main.pref.getBoolean("draw.rawgps.lines.force", layerName, false)); 319 342 drawGpsArrows.setSelected(Main.pref.getBoolean("draw.rawgps.direction", layerName, false)); … … 323 346 largeGpsPoints.setSelected(Main.pref.getBoolean("draw.rawgps.large", layerName, false)); 324 347 useGpsAntialiasing.setSelected(Main.pref.getBoolean("mappaint.gpx.use-antialiasing", false)); 348 325 349 drawRawGpsLinesActionListener.actionPerformed(null); 326 350 … … 337 361 case 3: colorTypeDirection.setSelected(true); break; 338 362 case 4: colorTypeTime.setSelected(true); break; 363 case 5: colorTypeHeatMap.setSelected(true); break; 339 364 default: Main.warn("Unknown color type: " + colorType); 340 365 } … … 342 367 colorTypeVelocityTune.setSelectedIndex(ccts == 10 ? 2 : (ccts == 20 ? 1 : 0)); 343 368 colorTypeVelocityTune.setEnabled(colorTypeVelocity.isSelected() && colorTypeVelocity.isEnabled()); 369 370 colorTypeHeatMapTune.setSelectedIndex(Main.pref.getInteger("draw.rawgps.heatmap.colormap", layerName, 0)); 371 colorTypeHeatMapTune.setEnabled(colorTypeHeatMap.isSelected() && colorTypeHeatMap.isEnabled()); 372 344 373 colorDynamic.setSelected(Main.pref.getBoolean("draw.rawgps.colors.dynamic", layerName, false)); 345 374 colorDynamic.setEnabled(colorTypeVelocity.isSelected() || colorTypeDilution.isSelected()); … … 386 415 Main.pref.put("draw.rawgps.large"+layerNameDot, largeGpsPoints.isSelected()); 387 416 Main.pref.put("draw.rawgps.linewidth"+layerNameDot, drawLineWidth.getText()); 417 Main.pref.put("draw.rawgps.lines.alpha-blend"+layerNameDot, drawLineWithAlpha.isSelected()); 418 388 419 Main.pref.put("mappaint.gpx.use-antialiasing", useGpsAntialiasing.isSelected()); 389 420 … … 404 435 } else if (colorTypeTime.isSelected()) { 405 436 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 4); 437 } else if (colorTypeHeatMap.isSelected()) { 438 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 5); 406 439 } else { 407 440 Main.pref.putInteger("draw.rawgps.colors"+layerNameDot, 0); … … 410 443 int ccti = colorTypeVelocityTune.getSelectedIndex(); 411 444 Main.pref.putInteger("draw.rawgps.colorTracksTune"+layerNameDot, ccti == 2 ? 10 : (ccti == 1 ? 20 : 45)); 445 446 Main.pref.putInteger("draw.rawgps.heatmap.colormap"+layerNameDot, colorTypeHeatMapTune.getSelectedIndex()); 447 412 448 return false; 413 449 }
Note:
See TracChangeset
for help on using the changeset viewer.