JAVA后端——依据离散点/格点生成GEOJSON以渲染色斑图

SpringBoot+PostGIS实现地理难抵点检索与地图可视化实战 在GIS开发与空间数据计算领域,如何高效求解区域内的“最远点”或“最难抵达位置”一直是行业关注的技术难点。地理难抵点(Pole of Inaccessibility)指区域内到边界或道路网距离最远的点,广泛应用于应急救援选址、通信基站盲区分析、旅游探险规划及公共服务评估。传统纯算法实现存在性能与维护成本瓶颈,而PostGIS作为强大的空间数据库扩展,将距离计算、格网生成、空间索引等能力下沉至数据层,配合SpringBoot后端框架可快速构建可检索、可交互的Web服务。本文从空间数据库基础概念出发,讲解难抵点 阅读详情

JAVA后端——依据离散点/格点生成GEOJSON以渲染色斑图

纯干货,一文既懂,相关解释都放进了代码的注释里,不多赘述

所需依赖

1.org.geotools相关依赖
2.jts相关依赖
3.netcdfAll相关依赖
4.其他常规JAVA依赖

代码

对geojson的源文件进行解析,以某一个要素为例,需要先获取对应的文件(一般为栅格文件),解析并取出对应的数据,形成栅格数据或进行特殊处理降噪后的离散点数据,再进行插值。
以下代码是以第一个时间维度为例做的解析,实际要根据需求修改代码

public static void main(String[] args) throws IOException {
        //生成geojosn的对应文件路径
        String filePath = "filePath";
        //读取文件
        NetcdfFile ncFile = NetcdfFile.open(filePath);

        // 打印变量信息
        NcFileUtils.printVariableInfo(ncFile, "x");

        // 获取维度信息
        int[] shape = NcFileUtils.getArrayShape(ncFile, "x");
        log.info("原始维度: {}", java.util.Arrays.toString(shape));

        // 读取经纬度(一维数组)
        float[] latArray = NcFileUtils.formatArray(NcFileUtils.readVariableTo1D(ncFile, "lat"));
        float[] lonArray = NcFileUtils.formatArray(NcFileUtils.readVariableTo1D(ncFile, "lon"));
        log.info("经度数量: {}, 纬度数量: {}", lonArray.length, latArray.length);

        // 根据维度选择合适的读取方法
        // 读取三维数据(保持完整结构)
        float[][][] data3D = NcFileUtils.formatArray3D(NcFileUtils.readVariableTo3D(ncFile, "x"));
        log.info("三维数据形状: {} x {} x {}", data3D.length, data3D[0].length, data3D[0][0].length);

        // 经纬度范围(根据边界数组计算的最值)
        double xMin = HUNAN_LON_MIN;   // 最小经度(西边界)
        double xMax = HUNAN_LON_MAX;   // 最大经度(东边界)
        double yMin = HUNAN_LAT_MIN;    // 最小纬度(南边界)
        double yMax = HUNAN_LAT_MAX;    // 最大纬度(北边界)

        //1: 3.14日 9: 3.22日
        float[][] data1 = data3D[0];
        List<Double> latList = new ArrayList<>();
        List<Double> lonList = new ArrayList<>();
        List<Double> valueList = new ArrayList<>();

        for (int i = 0; i < data1.length; i++) {

            double lat = latArray[i];
            for (int j = 0; j < data1[i].length; j++) {
                double lon = lonArray[j];
                if (lat < yMin || lat > yMax || lon < xMin || lon > xMax) {
                    continue;
                }
                double value = data1[i][j];
                latList.add(lat);
                lonList.add(lon);
                valueList.add(value);
//                log.info("经度: {}, 纬度: {}, 值: {}", lon, lat, value);
            }

        }
        try {
            ncFile.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        double[] xs = new double[lonList.size()];
        double[] ys = new double[latList.size()];
        double[] values = new double[valueList.size()];
        for (int i = 0; i < lonList.size(); i++) {
            xs[i] = BigDecimalUtil.roundToDecimalPlaces(lonList.get(i), 3);
            ys[i] = BigDecimalUtil.roundToDecimalPlaces(latList.get(i), 3);
            values[i] = BigDecimalUtil.roundToDecimalPlaces(valueList.get(i), 3);
        }
        log.info("xs size:{} ys size:{}", xs.length, ys.length);

是否需要对最后的geojson进行裁剪

        ShpBoundaryUtil.BoundaryResult boundaryResult = ShpBoundaryUtil.getBoundaryByFeatures(HUNAN_SHP_PATH);
        double[] clipYs = boundaryResult.getLatitudes();
        double[] clipXs = boundaryResult.getLongitudes();        

预期的栅格数据量大小,根据实际情况调整

        int xNum = 300;   // 经度方向格点数(更密集的网格)
        int yNum = 300;   // 纬度方向格点数

		// 无效值过滤
        double undefValue = -9999.0;

注意:将对数据进行插值,以下是几种算法的特点
/**
* IDW 临近点算法、固定最近N离散点数的插值,点约近权重越大
*/
IDW_NEIGHBOR,

/**
 * IDW 范围查找(kdTree 实现)检索以该点为中心、指定半径范围内的所有离散点,再用 IDW 计算,幂次衰减:权重随距离幂次(p)单调下降,无严格边界(即是受所有数据影响)
 * 属于 IDW_RADIUS中大数据量的优化方案
 */
IDW_RADIUS_KD_TREE,

/**
 * Cressman kdTree 指定半径范围内的所有离散点,非线性衰减:距离越近,权重增速越快,有明确边界(受范围内数据影响) 
 * Cressman中大数据量的优化方案
 */
CRESSMAN_KD_TREE,

插值并生成结果

        // 插值算法(从离散点插值到网格)
        InterpolateAlgorithm algorithm = InterpolateAlgorithm.IDW_NEIGHBOR;
//        InterpolateAlgorithm algorithm = null;

        // 定义颜色区间(适合气温范围)
        InterpolateColor.Interval interval = InterpolateColor.PRE_24H;

        // 输出类型:POLYGON(等值面)、POLYLINE(等值线)、IMAGE(图像)
        ContourOutType type = ContourOutType.POLYGON;
        // 调用 toJSON 方法
        JSONObject result = ContourUtil.toJSON(
                xs,
                ys,
                values,
                clipXs,
                clipYs,
                xMin,
                xMax,
                yMin,
                yMax,
                xNum,
                yNum,
                undefValue,
                algorithm,
                interval,
                type
        );

        // 输出结果
        System.out.println("生成的离散点插值 GeoJSON: ");
        System.out.println(result.toJSONString()
                .substring(0, Math.min(result.toJSONString().length(), 100)) +" ...");

        // 保存到文件
        ContourUtil.saveToFile("xxxxxxxx\\output.json", result);

若是离散数据,按照此方法执行,获取对应值范围的色卡,即geojosn的色卡,并处理离散点数据,数据分级以便于生成geojson

   /**
     * 离散点数据轮廓处理
     *
     * @param xs         经度
     * @param ys         纬度
     * @param values     观测值
     * @param clipXs     裁剪边界经度
     * @param clipYs     裁剪边界纬度
     * @param xMin       最小经度
     * @param xMax       最大经度
     * @param yMin       最小纬度
     * @param yMax       最大纬度
     * @param xNum       径向格点数
     * @param yNum       纬向格点数
     * @param undefValue 无效值
     * @param algorithm  插值算法
     * @param interval   轮廓色标值区间
     * @param type       输出类型
     * @return 结果
     */
    public JSONObject toJSON(
        double[] xs,
        double[] ys,
        double[] values,
        double[] clipXs,
        double[] clipYs,
        double xMin,
        double xMax,
        double yMin,
        double yMax,
        int xNum,
        int yNum,
        double undefValue,
        InterpolateAlgorithm algorithm,
        InterpolateColor.Interval interval,
        ContourOutType type
    ) {
        // 轮廓区间值
        double[] contourValues = interval.getValues();
        // 处理离散数据
        double[][] discreteData = processDiscreteValues(xs, ys, values, contourValues);

        return toJSON(
            discreteData,
            clipXs,
            clipYs,
            xMin,
            xMax,
            yMin,
            yMax,
            xNum,
            yNum,
            undefValue,
            algorithm,
            interval,
            type
        );
    }

    public double[][] processDiscreteValues(double[] xs, double[] ys, double[] values, double[] intervalValues) {
        double[][] discreteData = new double[xs.length][3];
        for (int i = 0; i < xs.length; i++) {
            discreteData[i][0] = xs[i];
            discreteData[i][1] = ys[i];
            if (values[i] <= intervalValues[0]) {
                discreteData[i][2] = intervalValues[0] - 1;
                continue;
            }
            if (values[i] >= intervalValues[intervalValues.length - 1]) {
                discreteData[i][2] = 1.5 * intervalValues[intervalValues.length - 1];
                continue;
            }
            for (int j = 0; j < intervalValues.length - 1; j++) {
                if (values[i] >= intervalValues[j] && values[i] < intervalValues[j + 1]) {
                    discreteData[i][2] = 0.5 * (intervalValues[j] + intervalValues[j + 1]);
                    break;
                }
            }
        }

        return discreteData;
    }

以分级后的数据生成插值获得网格数据、计算平滑轮廓线,是最后的geojson更加自然,最后输出等值面json

    /**
     * 离散点数据轮廓处理
     *
     * @param clipXs     裁剪边界经度
     * @param clipYs     裁剪边界纬度
     * @param xMin       最小经度
     * @param xMax       最大经度
     * @param yMin       最小纬度
     * @param yMax       最大纬度
     * @param xNum       径向格点数
     * @param yNum       纬向格点数
     * @param undefValue 无效值
     * @param algorithm  插值算法
     * @param interval   轮廓色标值区间
     * @param type       输出类型
     * @return 结果
     */
    public JSONObject toJSON(
        double[][] gridData,
        double[] clipXs,
        double[] clipYs,
        double xMin,
        double xMax,
        double yMin,
        double yMax,
        int xNum,
        int yNum,
        double undefValue,
        InterpolateAlgorithm algorithm,
        InterpolateColor.Interval interval,
        ContourOutType type
    ) {
        // 轮廓区间值
        double[] contourValues = interval.getValues();
        // 创建栅格坐标
        double[] gridX = new double[xNum];
        double[] gridY = new double[yNum];
        Interpolate.createGridXY_Num(xMin, yMin, xMax, yMax, gridX, gridY);

        long start = System.currentTimeMillis();
        if (algorithm != null) {
            // 插值获得网格数据
            gridData = interpolate(gridData, gridX, gridY, undefValue, algorithm);
        }
        log.info("插值花费时间{}", (System.currentTimeMillis() - start));
        // 追踪计算网格边界
        int[][] temp = new int[gridData.length][gridData[0].length];
        List<Border> borders = Contour.tracingBorders(gridData, gridX, gridY, temp, undefValue);

        // 追踪计算轮廓线
        List<PolyLine> contourLines = Contour.tracingContourLines(
            gridData,
            gridX,
            gridY,
            contourValues.length,
            contourValues,
            undefValue,
            borders,
            temp
        );

        // 平滑处理轮廓线
        List<PolyLine> lines = Contour.smoothLines(contourLines);
        if (ContourOutType.POLYLINE.equals(type)) {
            return toPolyLineJson(lines, clipXs, clipYs, interval);
        }

        // 追踪计算轮廓面
        List<Polygon> polygons = Contour.tracingPolygons(gridData, lines, borders, contourValues);
        // 输出等值面 GeoJSON
        if (ContourOutType.POLYGON.equals(type)) {
            return toPolygonJson(polygons, clipXs, clipYs, interval);
        }
        return new JSONObject();
    }

插值方法

    /**
     * 根据算法将离散点数据插值成网格数据
     *
     * @param discreteData 离散点数据
     * @param gridX        网格 X 坐标集合(eg: Lon List)
     * @param gridY        网格 Y 坐标集合(eg: Lat List)
     * @param undefValue   默认值
     * @param algorithm    算法 {@link InterpolateAlgorithm}
     * @return 插值后的网格数据
     */
    public double[][] interpolate(
        double[][] discreteData,
        double[] gridX,
        double[] gridY,
        double undefValue,
        InterpolateAlgorithm algorithm
    ) {
        // 定义网格数据
        double[][] gridData = new double[gridX.length][gridY.length];

        // 根据指定算法进行插值处理
        if (InterpolateAlgorithm.IDW_NEIGHBOR.equals(algorithm)) {
            gridData = Interpolate.interpolation_IDW_Neighbor(discreteData, gridX, gridY, 4, undefValue);
        } else if (InterpolateAlgorithm.IDW_RADIUS.equals(algorithm)) {
            gridData = Interpolate.interpolation_IDW_Radius(discreteData, gridX, gridY, 4, 2, undefValue);
        } else if (InterpolateAlgorithm.IDW_RADIUS_KD_TREE.equals(algorithm)) {
            gridData = Interpolate.idw_Radius_kdTree(discreteData, gridX, gridY, 4, 2, undefValue);
        } else if (InterpolateAlgorithm.CRESSMAN.equals(algorithm)) {
            List<Double> list = Arrays.asList(10D, 8D, 6D, 4D, 2D);
            gridData = Interpolate.cressman(discreteData, gridX, gridY, undefValue, list);
        } else if (InterpolateAlgorithm.CRESSMAN_KD_TREE.equals(algorithm)) {
            List<Double> list = Arrays.asList(10D, 8D, 6D, 4D, 2D);
            gridData = Interpolate.cressman_kdTree(discreteData, gridX, gridY, undefValue, list);
        }

        return gridData;
    }

根据interval拼geojosn的方法


    /**
     * 将 Polygons 根据数值区间转换为 GeoJSON
     *
     * @param polygons 
     * @param interval 
     * @return GeoJSON
     */
    private static JSONObject toPolygonJson(
        List<Polygon> polygons,
        double[] clipXs,
        double[] clipYs,
        InterpolateColor.Interval interval
    ) {
        List<PointD> clips = getClipPointList(clipXs, clipYs);
        if (!clips.isEmpty()) {
            polygons = Contour.clipPolygons(polygons, clips);
        }
        String features = polygons
            .stream()
            .map(polygon -> {
                List<String> lines = new ArrayList<>();
                lines.add("\"type\":\"Feature\"");
                List<String> coordinates = new ArrayList<>();
                PointD pointFirst = polygon.OutLine.PointList.get(0);
                Double firstX = NumberUtil.round(pointFirst.X, 6).doubleValue();
                Double firstY = NumberUtil.round(pointFirst.Y, 6).doubleValue();
                PointD pointLast = polygon.OutLine.PointList.get(polygon.OutLine.PointList.size() - 1);
                Double lastX = NumberUtil.round(pointLast.X, 6).doubleValue();
                Double lastY = NumberUtil.round(pointLast.Y, 6).doubleValue();
                double absX = Math.abs(NumberUtil.sub(firstX, lastX));
                if (absX > 0) {
                    pointLast.X = firstX;
                }
                double absY = Math.abs(NumberUtil.sub(firstY, lastY));
                if (absY > 0) {
                    pointLast.Y = firstY;
                }
                coordinates.add(
                    "[" +
                    polygon.OutLine.PointList
                        .stream()
                        .map(point ->
                            "[" +
                            NumberUtil.round(point.X, 6).doubleValue() +
                            "," +
                            NumberUtil.round(point.Y, 6).doubleValue() +
                            "]"
                        )
                        .collect(Collectors.joining(",")) +
                    "]"
                );
                if (polygon.HasHoles()) {
                    coordinates.add(
                        polygon.HoleLines
                            .stream()
                            .map(line -> {
                                PointD pointFirst1 = line.PointList.get(0);
                                Double firstX1 = NumberUtil.round(pointFirst1.X, 6).doubleValue();
                                Double firstY1 = NumberUtil.round(pointFirst1.Y, 6).doubleValue();
                                PointD pointLast1 = line.PointList.get(line.PointList.size() - 1);
                                Double lastX1 = NumberUtil.round(pointLast1.X, 6).doubleValue();
                                Double lastY1 = NumberUtil.round(pointLast1.Y, 6).doubleValue();
                                double absX1 = Math.abs(NumberUtil.sub(firstX1, lastX1));
                                if (absX1 > 0 && absX1 < 0.0001) {
                                    pointLast1.X = firstX1;
                                }
                                double absY1 = Math.abs(NumberUtil.sub(firstY1, lastY1));
                                if (absY1 > 0 && absY1 < 0.0001) {
                                    pointLast1.Y = firstY1;
                                }
                                return (
                                    "[" +
                                    line.PointList
                                        .stream()
                                        .map(point ->
                                            (
                                                "[" +
                                                NumberUtil.round(point.X, 6) +
                                                "," +
                                                NumberUtil.round(point.Y, 6) +
                                                "]"
                                            )
                                        )
                                        .collect(Collectors.joining(",")) +
                                    "]"
                                );
                            })
                            .collect(Collectors.joining(","))
                    );
                }
                lines.add(
                    "\"geometry\":{\"type\":\"Polygon\",\"coordinates\":[" + String.join(",", coordinates) + "]}"
                );

                String color = getRangeColor(interval, polygon.LowValue, polygon.IsHighCenter);
                lines.add("\"properties\":{\"color\":\"" + color + "\"}");

                return "{" + String.join(",", lines) + "}";
            })
            .collect(Collectors.joining(","));
        String result = "{\"type\":\"FeatureCollection\",\"features\":[" + features + "]}";
        return JSONObject.parseObject(result);
    }
网格数据不过多解释,代码如下

下集更精彩~



【GIS实战】Java服务端等值面生成:从Geotools数据插值到wContour边界裁剪 本文详细介绍了在Java服务端利用Geotools和wContour库生成等值面图的完整实战方案。针对GIS项目中离散点数据可视化需求,文章阐述了服务端生成等值面的必要性,并逐步解析了从数据插值、等值面追踪到边界裁剪的核心流程与性能优化策略,最终输出前端可直接渲染的GeoJSON数据。 阅读详情

相关推荐

Redis的一些事

Redis的一些事 Redis是什么 REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统,常被用作消息中间件,缓存服务器,数据库等。 大家对redis的第一印象一定是小,而且快,官方曾做过回复:使用redis时,几乎不存在CPU成为瓶颈的问题,redis主要受限于内存与网络。 RESP(Redis Serialization Protocol) redis的通讯协议是序列化协议,即通过RESP进行通讯,文本协议容易实

疯人愿 657

等值线图以及色斑图实现方式综述

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Markdown编辑器 你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用hel

weixin_51965860的博客 3846

别再只会regress了!用Stata的csdid命令搞定多期DID的完整实操指南

本文详细介绍了如何在Stata中使用csdid命令进行多期DID分析,解决传统DID方法在交错处理场景下的局限性。通过完整的实操指南,包括环境搭建、核心语法、结果解读和高阶应用,帮助研究者更准确地评估政策效果,适用于计量经济学和实证研究领域。

weixin_30236595的博客 582

GIS制作色斑图(等值面图)保姆级指导0基础小白

用GIS制作色斑图(等值面图)保姆级指导0基础小白,有边界文件和要素表格就能做!

weixin_71469386的博客 4062

AXI VIP配置全指南:从报错到成功仿真的完整流程(Vivado 2023版)

本文详细解析了在Vivado 2023环境中配置AXI Verification IP(VIP)进行协议仿真的完整流程。针对常见的include和import报错问题,提供了具体的解决方案和代码示例,指导用户从IP核创建、参数化配置,到构建可工作的仿真测试平台,最终实现成功仿真。

gpt4scribbler的博客 233

dify离线部署

以bge-m3为例,本地部署bge-m3首先在一台能连网的linux服务器上(部署有ollama)创建想要保存模型的文件夹编辑ollama.service,配置ollama模型的保存路径添加模型存储地址将models目录设置属主,必须做,否则ollama无法启动重新加载配置文件并重启ollama测试ollama 运行是否正常最后拉取 bge-m3可在/opt/LLMModels/bge_m3/models目录下看到拉取得模型使用tar命令压缩文件夹。

weixin_42538734的博客 3069

geotools中等值面的生成与OL3中的展示

http://blog.youkuaiyun.com/gisshixisheng/article/details/77547484

LZUGIS 1万+

28GHz毫米波滤波器设计实战:用SynMatrix快速搞定SIW带通滤波器(附完整参数)

本文详细介绍了如何使用SynMatrix工具链高效设计28GHz SIW带通滤波器,涵盖智能参数预测、多物理场联合优化和加工误差补偿等核心技术。通过实战案例和完整参数模板,帮助射频工程师快速实现毫米波滤波器设计,显著提升工作效率并避免反复迭代。

weixin_29284657的博客 496

用GeoTools实现shp+sld导出图片

概述:本文讲解通过Geotools实现用shp和sld导出图片。实现:生成后的图片实现代码:package com.lzugis.geotools; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; import jav...

weixin_30263277的博客 1146

表格数据学习的图神经网络综述

今天学习一篇发表在中科院一区期刊《ACM Computing Surveys》的综述文章《Graph Neural Networks for Tabular Data Learning: A Survey with Taxonomy & Directions》,该刊主要刊载计算机理论方法领域的系统性综述与教程论文,注重跨学科技术融合研究,最新的影响因子为28.0。本文的目的在于通过学习这篇文章,了解关于表格数据学习点图神经网络一些基础知识。

qq_41009600的博客 800

手把手教你用Qt5打造二次元游戏启动器(附鸣潮同款UI源码)

本文详细介绍了如何使用Qt5框架从零开始构建一个功能完整、UI风格贴近《鸣潮》的二次元游戏启动器。教程涵盖无边框窗口、动态背景、自定义控件绘制、多线程资源加载以及下载管理等核心模块的实现,并提供了可运行的源码参考,帮助C++开发者和Qt爱好者深入掌握现代桌面应用开发技术。

weixin_29291863的博客 265

Java后端基于离散点插值生成GEOJSON色斑图完整方案

在气象、环保、农业等业务中,经常需要将零散的监测站点数据转化为连续的专题色斑图,这背后依赖的是空间插值技术。插值算法能从已知离散点推算出未知位置的估计值,其中反距离加权(IDW)以原理简单、效果平滑、计算开销可控而成为工程首选。相比前端实时计算,由Java后端完成插值、格点化、多边形合并及GEOJSON组装,既能保障大数据量下的性能稳定,又可实现多端复用与结果缓存。这类能力广泛应用于温度、AQI、土壤墒情等要素的空间分布展示,前端通过Leaflet或ECharts加载GEOJSON即可快速渲染,极大提升地图

weixin_32715349的博客 250

winpcap无法安装提示新版本已经安装解决办法

问题显示如下该问题会导致ensp里的云识别不到网卡可能是因为之前安装了npcap,而且安装时勾选了第四个选项导致无法安装,需要完全卸载npcap解决办法:办法一:在控制面板的程序与卸载里面卸载npcap和winPcap,然后再安装winPcap,如果搜不到往下看办法二:在C:\Windows\SysWOW64目录下搜索wpcap.dll和packet.dll并重命名为wpcap.dll.old和packet.dll.old办法三:如果搜不到这两个文件需要安装win10Pcap才能找到这两个文件下载地址:Wi

qq_73202377的博客 3万+

Java后端生成GeoJSON色斑图的技术实现

地理空间数据可视化是GIS和气象领域的核心需求,其中色斑图通过颜色梯度直观展示数据分布。GeoJSON作为基于JSON的开放标准格式,因其良好的前端兼容性和网络传输效率,成为Web地图服务的首选数据格式。在技术实现上,通过空间插值算法(如IDW、克里金法)将离散点转化为连续场,再结合Marching Squares等值线生成技术,最终构建符合规范的Polygon要素集合。该方案在气象监测、环境质量分析等场景中,能有效替代传统GIS软件处理流程,实现动态数据的高效可视化。典型应用包括Leaflet等地图库的实

weixin_30516429的博客 232

PostgreSQL高可用之主备复制

多个PostgreSQL可协同工作,如果主库发生宕机备库将迅速进行接管并对外提供服务以实现高可用。本文将从主备复制、主备切换、故障转移等角度进行实际测试演练。第一章主备复制是基础,通过主备复制可以得到一个或多个相同的实例。在主备复制的基础上通过第二章主备切换介绍了如何手工将主库与备库互换角色。在第三章中,采用了Keepalived进行实时监测,在主库宕机后,使用主备切换中提到的命令使备库升级为主库并对外提供服务,以达到PostgreSQL高可用的目标。

asdasdsaff的博客 1348

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

Java后端生成GeoJSON色斑图:从坐标系到性能优化的完整实践

地理数据可视化在WebGIS、环保、气象等领域中越来越常见,而GeoJSON作为标准的地理数据交换格式,是连接原始数据与前端渲染的关键技术。理解其结构原理,掌握坐标系转换(如WGS84)、多边形构建及颜色映射等核心环节,能够帮助Java后端高效将离散点或格点数据转化为浏览器可识别的色斑图。该方案不仅能解决数据量导致的性能瓶颈,还能通过降采样和字段契约统一等工程化手段提升接口稳定性。无论是在需要与ArcGIS等桌面工具互验格式兼容性的场景,还是在多个Java后端项目合并时抽离公共模块来复用能力,这种技术路径都

weixin_31309419的博客 273

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Java后端实现GeoJSON色斑图动态生成与优化

空间数据可视化是GIS和气象监测领域的核心技术,其中色斑图(Choropleth Map)通过颜色渐变直观呈现数据分布。相比传统热力图,基于GeoJSON的矢量方案具有无级缩放、样式灵活和交互性强三大优势。实现原理上,后端通过自然邻域法等空间插值算法将离散点转化为连续面域,再编码为轻量级GeoJSON格式。该技术在环境监测等场景价值显著,如支持PM2.5数据的实时动态渲染。本文以Java技术栈为例,详解从离散点插值、坐标转换到GeoJSON优化的全流程,包含Leaflet前端集成方案与性能压测数据,最后给出

weixin_32715349的博客 157

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

php生成色斑图,等值线图以及色斑图实现方式综述

修改于2021/1/101、服务器模式通用的方式是基于Java + Geotools + wContour在服务端处理数据,适用业务如下:大范围高密度的空间数据插值服务器端可以设置定时任务,流水线处理原始数据,生成目标数据(图片或者GeoJSON数据)专题图输出服务器端负责上色、出图,前端负责叠加图片展示。气象数据需要通过鼠标坐标值在服务器端获取或者通过图片像素点颜色与颜色表映射得到。缺点是不利于...

weixin_30297493的博客 518

如何使用阿里云maven镜像仓库以及地址

maven项目一般都会设置自己的本地仓库与镜像仓库。 其中镜像仓库一般设置为国内的几大互联网巨头平台,当然有些公司会有属于自己的镜像仓库,但是阿里云的个人用了这么久,觉得最好。 设置方法: 1.在个人安装的maven路径下找到settings.xml,例如我的是E:\apache-maven-3.3.9\conf\settings.xml; 2.在此xml文件中找到标签; 3.在此标签内添加以下内...

疯人愿 1861

SonarLint代码质量管理工具的安装与使用

SonarLint初用 SonarLint的安装 安装一般有2种方式: 1.以下是常用的开发工具idea为例: 即通过File下拉框中的Settings中下载 2.在官网下载后安装: 同样在settings中可以从硬盘读取已下载的插件 安装好以后,需要进行一些基础设置: 一般你所在的公司或者项目组就会提供相应的sonarcloud或者sonarqube供你加入 输入指定的token 然后...

疯人愿 764

纯手写理解设计模式代码之工厂模式

抽象工厂模式属于创建型模式: 纯手写 package com.demo.abstractFactory; /** * 抽象工厂模式 * 创建型设计模式 * 就是将一类相同类型的产品抽象为产品族 * 例如将苹果、苹果树、苹果汁抽象为苹果工厂 * 这样生产这一产品系列的对象效率大大提升 * 抽象工厂和方法工厂的对比: * 工厂方法适用产生单一产品 * 抽象工厂适用生产大量同类产品,例如再抽象一类梨子水果产品,十分方便,但是有一缺点: * 例如在AbstractFactoryFruit下需要多

疯人愿 518

纯手写理解设计模式代码之代理模式

代理模式 代理模式属于结构型设计模式 静态代理模式 package com.demo.proxy; /** * 代理模式 * 结构型设计模式 * 三个角色:真实角色Target、代理角色Proxy、消费者Consumer * 静态代理模式: * 代理角色与真实角色耦合性太高,不适用 * 但是理解动态代理的第一步 *下面以房产出租为例:房主、中介、租客一一对应真实、代理、消费者 */ //租客 interface Person{ void rent(); } //房主 class

疯人愿 386

纯手写理解设计模式代码之原型模式

原型模式 也称为克隆模式,属于创建型模式 普通版 package com.demo.prototype; /** * 原型模式(克隆模式) * 创建型模式 * 就是通过原型对象返回一个完全相同或相近的对象,包括其中的属性值 * 可以在不知道对象的具体类型的情况下创造对象 * 并且对于那些创建十分耗时的对象来说,clone比new速度快 */ public class Prototype implements Cloneable{ //JDK中有实现原型模式的方法,但是该对象所对应的类必

疯人愿 312

纯手写理解设计模式代码之建造者模式

建造者模式同属于创建型模式 package com.demo.build; /** * 建造者模式 * 属于创建型模式 * 建造者模式与工厂模式相似,也是用来创建对象 * 建造者模式关键点在于建造和装配分离, * 建造者最终只会生成一个完整的对象,对象里面会分成好几个模块,建造者模式强调的是这个装配的过程。 * 而工厂模式有可能是会同时创建一个(简单工厂或者工厂方法模式)或者多个对象(抽象工厂模式),强调生产创建。 */ abstract class GunBuilder { //抽

疯人愿 255
上一篇: JAVA以SHP文件,切割一个数据集(GRB2、NC)中边界内的范围或数据
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值