Skip to content

Instantly share code, notes, and snippets.

@Roger8
Last active July 19, 2019 01:37
Show Gist options
  • Save Roger8/79e6212c23ef32f82731f9e048c9e5cc to your computer and use it in GitHub Desktop.
Save Roger8/79e6212c23ef32f82731f9e048c9e5cc to your computer and use it in GitHub Desktop.
heatmap 热点图
heatmap 热点图
package com.manager.heatmap;

import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Point;
import android.support.annotation.NonNull;
import android.util.Log;

import com.manager.db.PersonBean;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

public class HeatMapX {

    private int im_width = 0;
    private int im_heigth = 0;
    private int radius= 30;
    private Bitmap hotspot=null;
//    private Dictionary<Integer,Integer> circledat= null;
//    private int [][] circletemplate=null;
    private Map<Integer, Integer> circletemplate = new HashMap<Integer, Integer>();
    private List<WeightedLatLng> heatdata = null;
    private int [] htdat = null;
    private int [] htdat2 = null;
    private int colorsteps = 240;
    private float [][] colors = null;
    private int [][] mdata = null;

    public void build(int im_width, int im_heigth){
        this.im_heigth = im_heigth;
        this.im_width = im_width;
        this.hotspot =  Bitmap.createBitmap(this.im_width,this.im_heigth, Bitmap.Config.ARGB_8888);
        this.htdat = new int[im_width*im_heigth];
        this.htdat2 = new int[im_width*im_heigth];
        this.make_colors(240);
        this.make_circle(this.radius, this.im_width);
    }

    public Bitmap getHeatmap(){
        return this.hotspot;
    }

    public void genheatdata(List<PersonBean> mDetailData){
//        this.mdata = new int[mDetailData.size()][3];

    // 统计密度
        Map<String, Integer> locstr = new HashMap<String, Integer>();
        for(PersonBean pb : mDetailData) {
            float[] bx = pb.getBbox();
            int cx = (int) ((bx[0] + bx[2]) / 2f);
            int cy = (int) ((bx[1] + bx[3]) / 2f);

            String tmp_loc = String.format("%d,%d", cx, cy);
            Integer count = locstr.get(tmp_loc);
            count = (count == null) ? 1 : count + 1;
            locstr.put(tmp_loc, count);
        }
        // 生成数据
        this.mdata = new int[locstr.size()][3];
        int i=0;
        for(Map.Entry<String,Integer> m: locstr.entrySet()) {
            String tmp_loc = m.getKey();
            String[] xy = tmp_loc.split(",");
            int cx = Integer.valueOf(xy[0]);
            int cy = Integer.valueOf(xy[1]);
            int count = m.getValue();
            mdata[i][0] = cx;
            mdata[i][1] = cy;
            mdata[i][2] = count;
            i++;
    }
}

    public void heatmap(){
//        this.make_circle(this.radius, this.im_width);
        for(int i=0;i<this.mdata.length;i++){
            int x = this.mdata[i][0];
            int y = this.mdata[i][1];
            int count = this.mdata[i][2];
            if(x<0 || x>= this.im_width || y<=0 || y>=this.im_heigth){
                continue;
            }
            this.doheat(this.htdat2,x,y,count,this.circletemplate);
        }

        rescaleheatdata(htdat2);

        this.paint_heat();
    }

    public void doheat(int [] hdata, int x, int y, int n, Map<Integer,Integer> template){
        int dlen = hdata.length;
        int p = this.im_width*y+x;
        for (Map.Entry<Integer , Integer> et: template.entrySet() )
        {
            Integer ip = et.getKey();
            Integer iv = et.getValue();
            int p2 = p+ ip;
            if(p2<dlen && p2>=0){
                hdata[p2] += iv*n;
            }
        }
    }

    public int getmaxv(int[] heatdata){
        int maxv= 0;
        for(int i=0;i<heatdata.length;i++){
            if(heatdata[i]>maxv){
                maxv = heatdata[i];
            }
        }
        return maxv;
    }

    public void rescaleheatdata(int [] heatdata){
        float max_v = getmaxv(heatdata);
        for(int i=0;i<heatdata.length;i++){
            float r = this.colorsteps/max_v;
            htdat[i] = (int)(heatdata[i]*r)-1;
        }
    }

    public  void paint_heat(){
        int msize = this.im_heigth*im_width;
        for(int i=0;i<msize;i++){
            int v = htdat[i];
            if(v>0){
                float [] color = this.colors[v];
                int row = i/this.im_width;
                int col = i%this.im_width;

                float alpha = color[2];
                if(alpha>50){
                    alpha = 255-255f*(alpha-50)/50f;
                    this.hotspot.setPixel(col, row, Color.argb((int)alpha,0,0,255));
                }else{
                    int [] rgb = HSL2RGBNew(color[0],color[1]/100f,color[2]/100f);
//                    this.hotspot.setPixel(col, row, Color.argb((int)alpha, rgb[0],rgb[1],rgb[2]));
                    this.hotspot.setPixel(col, row, Color.rgb( rgb[0],rgb[1],rgb[2]));
                }
            }
        }
        Log.i("heatmap", "paint done.");
    }

    int [] HSL2RGBNew(float H, float S, float L){
        int R=0,G=0,B=0 ;
        float [] rgb = new float[3];
        float q = 0f;
        float p=0f;
        float hk = 0f;
        float tr=0f;
        float tg=0f;
        float tb = 0f;
        if(S>0){
            float v_1_3 = 1f/3;
            float v_1_6 = 1f/6;
            float v_2_3 = 2f/3;

            if(L < 0.5 ){
                q=L*(1f+S);
            }else{
                q=L+S-(L*S);
            }
            p=L*2f-q;
            hk = H/360f;
            tr = hk+v_1_3;
            tg = hk;
            tb = hk-v_1_3;

            rgb[0] = tr;
            rgb[1] = tg;
            rgb[2] = tb;

            for(int i=0;i<3;i++){
                rgb[i] = onec(rgb[i]);
            }

            for(int i=0;i<3;i++) {
                float tc = rgb[i];

                if(tc<v_1_6){
                    rgb[i] = p+(q-p)*6f*tc;
                }else if(tc<0.5 && tc>=v_1_6){
                    rgb[i] = q;
                }else if(tc>=0.5 && tc<v_2_3){
                    rgb[i] = p+((q-p)*6f*(v_2_3-tc));
                }else{
                    rgb[i] = p;
                }
            }

            R = (int)(rgb[0]*255);
            G = (int)(rgb[1]*255);
            B = (int)(rgb[2]*255);

        }else{
            R=G=B = (int)(L*255);
        }
        int[] rgbint = {R,G,B};
        return rgbint;
    }

    float onec(float tc){
        float out = 0f;
        if(tc<0){
            out = tc+1f;
        }else if(tc>1){
            out = tc-1f;
        }else{
            out = tc;
        }
        return out;
    }

    float [] HSL2RGB(float H,float S,float L)
    {
        float R,G,B;
        float var_1, var_2;
        if (S == 0)                       //HSL values = 0 ÷ 1
        {
            R = L * 255.0f;                   //RGB results = 0 ÷ 255
            G = L * 255.0f;
            B = L * 255.0f;
        }
        else
        {
            if (L < 0.5) var_2 = L * (1 + S);
            else         var_2 = (L + S) - (S * L);

            var_1 = 2.0f * L - var_2;

            R = 255.0f * Hue2RGB(var_1, var_2, H + (1.0f / 3.0f));
            G = 255.0f * Hue2RGB(var_1, var_2, H);
            B = 255.0f * Hue2RGB(var_1, var_2, H - (1.0f / 3.0f));
        }
        float [] color_rgb = {R,G,B};
        return color_rgb;
    }
    //---------------------------------------------------------------------------
    float Hue2RGB(float v1, float v2, float vH)
    {
        if (vH < 0) vH += 1f;
        if (vH > 1) vH -= 1f;
        if (6.0 * vH < 1) return (float)(v1 + (v2 - v1) * 6.0 * vH);
        if (2.0 * vH < 1) return v2;
        if (3.0 * vH < 2) return (float)(v1 + (v2 - v1) * ((2.0 / 3.0) - vH) * 6.0f);
        return (v1);
    }

    public void make_colors(int n){

        colors = new float [n][3];
        int n1 = (int)(n*0.4f);
        int n2 = n-n1;
        for(int i =0; i<n1;i++){
            colors[i][0] = 240;
            colors[i][1] = 100;
            colors[i][2] = 100*(n1-i/2f)/n1;
        }
        for(int i =0; i<n2;i++){
            colors[n1+i][0] = n*(1-i*1f/n2);
            colors[n1+i][1] = 100;
            colors[n1+i][2] = 50;
        }
    }

    public void circle8(int ix, int iy,int v, int w){
        List<Point> points = new ArrayList<>();
        points.add(new Point(ix,iy));
        points.add(new Point(-ix,iy));
        points.add(new Point(ix,-iy));
        points.add(new Point(-ix,-iy));
        points.add(new Point(iy,ix));
        points.add(new Point(-iy,ix));
        points.add(new Point(iy,-ix));
        points.add(new Point(-iy,-ix));

        for(Point pt : points){
            int p = pt.y*w + pt.x;
//            circledat.put(p, v);
            circletemplate.put(p,v);
        }

    }


    public void make_circle(int radius , int w){
        int x = 0;
        int y = radius;
        int d = 3 - (radius<<1);
        while(x<=y){
            for(int _y=x;_y<y+1;_y++){
                circle8(x,_y, y+1-_y, w);
            }
            if(d<0){
                d += (x<<2)+6;
            }else{
                d+=((x-y)<<2)+10;
                y -= 1;
            }
            x += 1;
        }
    }
}

参考: 1.HeatMapForAndroid 2.pyheatmap

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment