Ticket #13124: josm_ticket_13124_gpx_heat_map_by_kidelo_v3.patch

File josm_ticket_13124_gpx_heat_map_by_kidelo_v3.patch, 9.7 KB (added by kidelo, 7 years ago)

GPX Heat Map Extension by kidelo, version 3

  • src/org/openstreetmap/josm/gui/layer/gpx/GpxDrawHelper.java

     
    742742        // 3rd. determine current paint parameters -----------------------------
    743743
    744744        // alpha value is based on zoom and line with combined with global layer alpha
    745         float theLineAlpha = Math.min(Math.max((0.50f/(float) zoomScale)/(globalLineWidth + 1), 0.001f), 0.50f) * layerAlpha;
     745        float theLineAlpha = Math.min(Math.max((0.50f/(float) zoomScale)/(globalLineWidth + 1), 0.01f), 0.50f) * layerAlpha;
    746746        final int theLineWith = (int) (lineWidth / zoomScale) + 1;
    747747
    748748        // 4th setup virtual paint area ----------------------------------------
     
    833833            int alpha = (int) (Math.sin(i * mapTo90Deg) * 255);
    834834
    835835            // alpha with pre-offset, first color -> full transparent
    836             alpha = i > 0 ? (75 + alpha) : 0;
     836            alpha = i > 0 ? (10 + alpha) : 0;
    837837
    838838            // shrink to maximum bound
    839839            if (alpha > 255) {
     
    854854    }
    855855
    856856    /**
     857     * Creates a darker color
     858     * @param in        Color object
     859     * @param adjust    darker adjustment amount
     860     * @return          new Color
     861     */
     862    protected static Color darkerColor(Color in, float adjust) {
     863
     864        final float r = ((float) in.getRed()/255);
     865        final float g = ((float) in.getGreen()/255);
     866        final float b = ((float) in.getBlue()/255);
     867
     868        return new Color(r*adjust, g*adjust, b*adjust);
     869    }
     870
     871    /**
    857872     * Creates a colormap by using a static color map with 1..n colors (RGB 0.0 ..1.0)
    858873     * @param str the filename (without extension) to look for into data/gpx
    859874     * @return the parsed colormap
     
    899914        if (colorList.isEmpty()) {
    900915            colorList.add(Color.BLACK);
    901916            colorList.add(Color.WHITE);
     917        } else {
     918            // add additional darker elements to end of list
     919            final Color lastColor = colorList.get(colorList.size() - 1);
     920            colorList.add(darkerColor(lastColor, 0.975f));
     921            colorList.add(darkerColor(lastColor, 0.950f));
    902922        }
    903923
    904924        return createColorLut(colorList.toArray(new Color[ colorList.size() ]));
     
    924944        // set initial values
    925945        gB.setStroke(backStroke); gB.setComposite(backComp);
    926946
     947        // get last point in list
     948        final WayPoint lastPnt = !listSegm.isEmpty() ? listSegm.get(listSegm.size() - 1) : null;
     949
    927950        // for all points, draw single lines by using optimize drawing
    928951        for (WayPoint trkPnt : listSegm) {
    929952
    930             // something to paint or color changed (new segment needed, decrease performance ;-()
    931             if (!trkPnt.drawLine && !heatMapPolyX.isEmpty()) {
     953            // get transformed coordinates
     954            final Point paintPnt = mv.getPoint(trkPnt.getEastNorth());
    932955
     956            // end of line segment or end of list reached
     957            if (!trkPnt.drawLine || (lastPnt == trkPnt)) {
     958
    933959                // convert to primitive type
    934960                final int[] polyXArr = heatMapPolyX.stream().mapToInt(Integer::intValue).toArray();
    935961                final int[] polyYArr = heatMapPolyY.stream().mapToInt(Integer::intValue).toArray();
     
    945971                    gB.setStroke(backStroke); gB.setComposite(backComp);
    946972                }
    947973
    948                 // drop used pints
     974                // drop used points
    949975                heatMapPolyX.clear(); heatMapPolyY.clear();
     976            }
    950977
    951             } else {
    952 
    953                 // get transformed coordinates
    954                 final Point paintPnt = mv.getPoint(trkPnt.getEastNorth());
    955 
    956                 // store only the integer part (make sense because pixel is 1:1 here)
    957                 heatMapPolyX.add((int) paintPnt.getX());
    958                 heatMapPolyY.add((int) paintPnt.getY());
    959             }
     978            // store only the integer part (make sense because pixel is 1:1 here)
     979            heatMapPolyX.add((int) paintPnt.getX());
     980            heatMapPolyY.add((int) paintPnt.getY());
    960981        }
    961982    }
    962983
     
    965986     * @param g               the common draw object to use
    966987     * @param imgGray         gray scale input image
    967988     * @param sampleRaster    the line with for drawing
     989     * @param outlineWidth     line width for outlines
    968990     */
    969     private void drawHeatMapGrayMap(Graphics2D g, BufferedImage imgGray, int sampleRaster) {
     991    private void drawHeatMapGrayMap(Graphics2D g, BufferedImage imgGray, int sampleRaster, int outlineWidth) {
    970992
    971993        final int[] imgPixels = ((DataBufferInt) imgGray.getRaster().getDataBuffer()).getData();
    972994
    973995        // samples offset and bounds are scaled with line width derived from zoom level
    974         final int offX = Math.max(1, sampleRaster / 2);
    975         final int offY = Math.max(1, sampleRaster / 2);
     996        final int offX = Math.max(1, sampleRaster);
     997        final int offY = Math.max(1, sampleRaster);
    976998
    977999        final int maxPixelX = imgGray.getWidth();
    9781000        final int maxPixelY = imgGray.getHeight();
    9791001
     1002        // always full or outlines at big samples rasters
     1003        final boolean drawOutlines = (outlineWidth > 0) && ((0 == sampleRaster) || (sampleRaster > 8));
     1004
     1005        // backup stroke
     1006        final Stroke oldStroke = g.getStroke();
     1007
     1008        // use basic stroke for outlines and default transparency
     1009        g.setStroke(new BasicStroke(outlineWidth));
     1010
    9801011        int lastPixelY = 0;
    9811012        int lastPixelColor = 0;
    9821013
     
    10001031
    10011032                // restart -> use initial sample
    10021033                if (0 == y) {
    1003                     lastPixelY = 0; lastPixelColor = thePixelColor;
     1034                    lastPixelY = 0; lastPixelColor = thePixelColor - 1;
    10041035                }
    10051036
    1006                 // different color to last one ?
    1007                 if (Math.abs(lastPixelColor - thePixelColor) > 1) {
     1037                boolean bDrawIt = false;
    10081038
    1009                     // draw only foreground pixels, skip small variations
    1010                     if (lastPixelColor > 1+1) {
     1039                // when one of segment is mapped to black
     1040                bDrawIt = bDrawIt || (lastPixelColor == 0) || (thePixelColor == 0);
    10111041
     1042                // different color
     1043                bDrawIt = bDrawIt || (Math.abs(lastPixelColor-thePixelColor) > 0);
     1044
     1045                // when line is finished draw always
     1046                bDrawIt = bDrawIt || (y >= (maxPixelY-offY));
     1047
     1048                if (bDrawIt) {
     1049
     1050                    // draw only foreground pixels
     1051                    if (lastPixelColor > 0) {
     1052
    10121053                        // gray to RGB mapping
    10131054                        g.setColor(heatMapLutColor[ lastPixelColor ]);
    10141055
    1015                         // start point for draw (
    1016                         int yN = lastPixelY > 0 ? lastPixelY : y;
    1017 
    10181056                        // box from from last Y pixel to current pixel
    1019                         if (offX < sampleRaster) {
    1020                             g.fillRect(yN, x, offY + y - yN, offX);
     1057                        if (drawOutlines) {
     1058                            g.drawRect(lastPixelY, x, offY + y - lastPixelY, offX);
    10211059                        } else {
    1022                             g.drawRect(yN, x, offY + y - yN, offX);
     1060                            g.fillRect(lastPixelY, x, offY + y - lastPixelY, offX);
    10231061                        }
    10241062                    }
     1063
    10251064                    // restart detection
    10261065                    lastPixelY = y; lastPixelColor = thePixelColor;
    10271066                }
    10281067            }
    10291068        }
     1069
     1070        // recover
     1071        g.setStroke(oldStroke);
    10301072    }
    10311073
    10321074    /**
     
    10411083        final Rectangle screenBounds = g.getDeviceConfiguration().getBounds();
    10421084        final double zoomScale = mv.getScale();
    10431085
    1044         // adjust global settings
    1045         final int globalLineWidth = Math.min(Math.max(lineWidth, 1), 20);
     1086        // adjust global settings ( zero = default line width )
     1087        final int globalLineWidth = (0 == lineWidth) ? 1 : Math.min(Math.max(lineWidth, 1), 20);
    10461088
    10471089        // 1st setup virtual paint area ----------------------------------------
    10481090
     
    10691111        // 2nd. determine current scale factors -------------------------------
    10701112
    10711113        // the line width (foreground: draw extra small footprint line of track)
    1072         final int lineWidthB = Math.max((int) (globalLineWidth / zoomScale) + 1, 2);
     1114        final int lineWidthB = (int) Math.max(1.5f * (globalLineWidth / zoomScale) + 1, 2);
    10731115        final int lineWidthF = lineWidthB > 2 ? (globalLineWidth - 1) : 0;
    10741116
    10751117        // recalculation of image needed
     
    10861128            heatMapGraph2d.clearRect(0, 0, heatMapImgGray.getWidth(), heatMapImgGray.getHeight());
    10871129
    10881130            // alpha combines both values, therefore the foreground shall be lighter
    1089             final float lineAlphaB = Math.min(Math.max((0.40f/(float) zoomScale)/(globalLineWidth + 1), 0.001f), 0.50f);
     1131            final float lineAlphaB = Math.min(Math.max((0.40f/(float) zoomScale)/(globalLineWidth + 1), 0.01f), 0.40f);
    10901132            final float lineAlphaF = lineAlphaB / 1.5f;
    10911133
    10921134            // derive draw parameters and draw
     
    11031145        }
    11041146
    11051147        // 4th. Draw data on target layer, map data via color lookup table --------------
    1106         drawHeatMapGrayMap(g, heatMapImgGray, lineWidthB);
     1148        drawHeatMapGrayMap(g, heatMapImgGray, lineWidthB > 2 ? lineWidthB / 2 : 1, lineWidth > 2 ? lineWidth-2 : 1);
    11071149    }
    11081150
    11091151    /**