根据条件筛选坐标点,并从取出的点位中获取最外围可以组成凸多边形的点位

根据条件筛选坐标点,并从取出的点位中获取最外围可以组成凸多边形的点位

具体需求根据街道中的单据量过滤5公里范围内,订单用户量80%范围的街道,并画出凸多边形
算法思路
1、根据某点过滤范围内的坐标

private void filterOverLimit(List<ShopSalesStreetPoint> radiationPointList, Point2D.Double shopPoint) {
        ShopSalesStreetPoint point0 = radiationPointList.get(0);
        Point2D.Double aDouble = new Point2D.Double(point0.getX(), point0.getY());
        Iterator<ShopSalesStreetPoint> it = radiationPointList.iterator();
        while (it.hasNext()) {
            ShopSalesStreetPoint streetPoint = it.next();
            double distance = DiscretePointUtil.countPointDistance(aDouble, new Point2D.Double(streetPoint.getX(), streetPoint.getY()));
            if (distance > 5000) {
                it.remove();
            }
        }
    }

2、递归
首先创建第一个点并将订单量返回用于统计,默认点位数组根据订单用户量从大到小排序

private BigDecimal processFirstPoint(List<ShopSalesStreetPoint> allStreetPointList, List<ShopSalesStreetPoint> pointList) {
        //提前计算第一个节点
        ShopSalesStreetPoint firstPoint = allStreetPointList.get(0);
        pointList.add(firstPoint);
        BigDecimal checkValue = firstPoint.getValue();
        //移除第一个
        allStreetPointList.remove(0);
        return checkValue;
    }

计算阈值,达到80%阈值则返回

  //达到阈值则返回
  if (checkThresholdValue(checkValue, allValue)) {
      return selectedPoint2DList;
  }
  public static boolean checkThresholdValue(BigDecimal check, BigDecimal all) {
        //四舍五入不进位RoundingMode.DOWN
        return check.divide(all, 3, RoundingMode.DOWN).multiply(new BigDecimal(100)).compareTo(new BigDecimal(VALUE_ACCOUNTED)) >= 0;
    }
 //执行后续
        selectedPoint2DList = process(checkValue, allValue, allStreetPointList, selectedPoint2DList);

从已选点位中选取最小凸多边形,并且输出排序好的点位

private List<ShopSalesStreetPoint> getMinimumBoundingPolygon(List<ShopSalesStreetPoint> selectedPoint2DList) {
        if (selectedPoint2DList.size() > 2) {
            selectedPoint2DList.forEach(point -> point.setFounded(false));
            selectedPoint2DList = MinimumBoundingPolygon.findSmallestPolygon(selectedPoint2DList);
        }
        return selectedPoint2DList;
    }

process方法为递归方法具体内容如下:

private List<ShopSalesStreetPoint> process(BigDecimal checkValue, BigDecimal allValue,
                                               List<ShopSalesStreetPoint> restStreetPointList, List<ShopSalesStreetPoint> selectedPoint2DList) {
        //达到阈值则返回
        if (checkThresholdValue(checkValue, allValue)) {
            return selectedPoint2DList;
        }
        ShopSalesStreetPoint curPoint = restStreetPointList.get(0);
        checkValue = checkValue.add(curPoint.getValue());
        //达到阈值则返回
        if (checkThresholdValue(checkValue, allValue)) {
            selectedPoint2DList = getMinimumBoundingPolygon(selectedPoint2DList);
            return selectedPoint2DList;
        }
        selectedPoint2DList.add(curPoint);
        //根据已有点位获取最大多边形
        if (selectedPoint2DList.size() > 2) {
            selectedPoint2DList = getMinimumBoundingPolygon(selectedPoint2DList);
        }
        //达到阈值则返回
        if (checkThresholdValue(checkValue, allValue)) {
            return selectedPoint2DList;
        }
        //移除第一个进入判断将范围内的所有点移除,并加入总额返回
        restStreetPointList.remove(0);
        //所有节点循环结束退出
        if (restStreetPointList.isEmpty()) {
            return selectedPoint2DList;
        }
        checkValue = removeRestStreetPoint(checkValue, selectedPoint2DList, restStreetPointList);
        //达到阈值则返回
        if (checkThresholdValue(checkValue, allValue)) {
            return selectedPoint2DList;
        }
        if (restStreetPointList.isEmpty()) {
            return selectedPoint2DList;
        }
        selectedPoint2DList = process(checkValue, allValue, restStreetPointList, selectedPoint2DList);
        return selectedPoint2DList;
    }

递归主函数中用到的工具类如下

package cn.com.gome.shop.analyze.backend.service.assistant;

import cn.com.gome.shop.analyze.backend.data.assistant.ShopSalesStreetPoint;
import org.springframework.stereotype.Service;

import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Service
public class PointService {


    /**
     * 是否有 横断<br/>
     * 参数为四个点的坐标
     *
     * @param px1
     * @param py1
     * @param px2
     * @param py2
     * @param px3
     * @param py3
     * @param px4
     * @param py4
     * @return
     */
    public static boolean isIntersect(double px1, double py1, double px2, double py2, double px3, double py3, double px4,
                                      double py4) {
        boolean flag = false;
        double d = (px2 - px1) * (py4 - py3) - (py2 - py1) * (px4 - px3);
        if (d != 0) {
            double r = ((py1 - py3) * (px4 - px3) - (px1 - px3) * (py4 - py3)) / d;
            double s = ((py1 - py3) * (px2 - px1) - (px1 - px3) * (py2 - py1)) / d;
            if ((r >= 0) && (r <= 1) && (s >= 0) && (s <= 1)) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 目标点是否在目标边上边上<br/>
     *
     * @param px0 目标点的经度坐标
     * @param py0 目标点的纬度坐标
     * @param px1 目标线的起点(终点)经度坐标
     * @param py1 目标线的起点(终点)纬度坐标
     * @param px2 目标线的终点(起点)经度坐标
     * @param py2 目标线的终点(起点)纬度坐标
     * @return
     */
    public static boolean isPointOnLine(double px0, double py0, double px1, double py1, double px2, double py2) {
        boolean flag = false;
        double ESP = 1e-9;//无限小的正数
//        if ((Math.abs(Multiply(px0, py0, px1, py1, px2, py2)) < ESP) && ((px0 - px1) * (px0 - px2) <= 0)
//                && ((py0 - py1) * (py0 - py2) <= 0)) {
//            flag = true;
//        }

        if (((px0 - px1) * (py1 - py2)) == ((px1 - px2) * (py0 - py1)) && (px0 >= min(px1, px2) && px0 <= max(px1, px2))
                && ((py0 >= min(py1, py2)) && (py0 <= max(py1, py2)))) {
            flag = true;
        }
        return flag;
    }

    public static Double min(Double d1, Double d2) {
        if (d1 < d2) {
            return d1;
        }
        return d2;
    }

    public static Double max(Double d1, Double d2) {
        if (d1 > d2) {
            return d1;
        }
        return d2;
    }

    public static double Multiply(double px0, double py0, double px1, double py1, double px2, double py2) {
        return ((px1 - px0) * (py2 - py0) - (px2 - px0) * (py1 - py0));
    }

    /**
     * 判断目标点是否在多边形内(由多个点组成)<br/>
     * 备用方案
     *
     * @param px        目标点的经度坐标
     * @param py        目标点的纬度坐标
     * @param polygonXA 多边形的经度坐标集合
     * @param polygonYA 多边形的纬度坐标集合
     * @return
     */
    @Deprecated
    public static boolean isPointInPolygon(double px, double py, ArrayList<Double> polygonXA, ArrayList<Double> polygonYA) {
        boolean isInside = false;
        double ESP = 1e-9;
        int count = 0;
        double linePoint1x;
        double linePoint1y;
        double linePoint2x = 180;
        double linePoint2y;

        linePoint1x = px;
        linePoint1y = py;
        linePoint2y = py;

        for (int i = 0; i < polygonXA.size() - 1; i++) {
            double cx1 = polygonXA.get(i);
            double cy1 = polygonYA.get(i);
            double cx2 = polygonXA.get(i + 1);
            double cy2 = polygonYA.get(i + 1);
            //如果目标点在任何一条线上
            if (isPointOnLine(px, py, cx1, cy1, cx2, cy2)) {
                return true;
            }
            //如果线段的长度无限小(趋于零)那么这两点实际是重合的,不足以构成一条线段
            if (Math.abs(cy2 - cy1) < ESP) {
                continue;
            }
            //第一个点是否在以目标点为基础衍生的平行纬度线
            if (isPointOnLine(cx1, cy1, linePoint1x, linePoint1y, linePoint2x, linePoint2y)) {
                //第二个点在第一个的下方,靠近赤道纬度为零(最小纬度)
                if (cy1 > cy2)
                    count++;
            }
            //第二个点是否在以目标点为基础衍生的平行纬度线
            else if (isPointOnLine(cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y)) {
                //第二个点在第一个的上方,靠近极点(南极或北极)纬度为90(最大纬度)
                if (cy2 > cy1)
                    count++;
            }
            //由两点组成的线段是否和以目标点为基础衍生的平行纬度线相交
            else if (isIntersect(cx1, cy1, cx2, cy2, linePoint1x, linePoint1y, linePoint2x, linePoint2y)) {
                count++;
            }
        }
        if (count % 2 == 1) {
            isInside = true;
        }

        return isInside;
    }


    public static boolean isInOnLine(Double pointLon, Double pointLat, Double lon1, Double lon2,
                                     Double lat1, Double lat2) {
        Line2D.Double aDouble = new Line2D.Double(lon1, lat1, lon2, lat2);
        double v = aDouble.ptLineDist(pointLon, pointLat);
        return v > 0;
    }

    /**
     * 判断是否在多边形区域内
     *
     * @param pointLon 要判断的点的纵坐标
     * @param pointLat 要判断的点的横坐标
     * @param lons     区域各顶点的纵坐标数组
     * @param lats     区域各顶点的横坐标数组
     * @return
     */
    public static boolean isInPolygon(Double pointLon, Double pointLat, Double[] lons,
                                      Double[] lats) {
        return isInPolygon(pointLon, pointLat, Arrays.asList(lons), Arrays.asList(lats));
    }

    /**
     * 判断是否在多边形区域内
     *
     * @param pointLon 要判断的点的纵坐标
     * @param pointLat 要判断的点的横坐标
     * @param lons     区域各顶点的纵坐标数组
     * @param lats     区域各顶点的横坐标数组
     * @return
     */
    public static boolean isInPolygon(Double pointLon, Double pointLat, List<Double> lons,
                                      List<Double> lats) {
        // 将要判断的横纵坐标组成一个点
        Point2D.Double point = new Point2D.Double(pointLon, pointLat);
        // 将区域各顶点的横纵坐标放到一个点集合里面
        List<Point2D.Double> pointList = new ArrayList<Point2D.Double>();
        for (int i = 0; i < lons.size(); i++) {
            Point2D.Double polygonPoint = new Point2D.Double(lons.get(i), lats.get(i));
            pointList.add(polygonPoint);
        }
        return check(point, pointList);
    }

    /**
     * 判断点是否在多边形区域内
     *
     * @param checkStreetPoint
     * @param streetPointList
     * @return
     */
    public static boolean isInPolygon(Point2D.Double checkStreetPoint, List<ShopSalesStreetPoint> streetPointList) {
        // 将区域各顶点的横纵坐标放到一个点集合里面
        List<Point2D.Double> point2DList = new ArrayList<Point2D.Double>();
        for (ShopSalesStreetPoint streetPoint : streetPointList) {
            Point2D.Double polygonPoint = new Point2D.Double(streetPoint.getY(), streetPoint.getX());
            point2DList.add(polygonPoint);
        }
        return check(checkStreetPoint, point2DList);
    }

    /**
     * 一个点是否在多边形内
     *
     * @param point   要判断的点的横纵坐标
     * @param polygon 组成的顶点坐标集合
     * @return
     */
    private static boolean check(Point2D.Double point, List<Point2D.Double> polygon) {
        GeneralPath generalPath = new GeneralPath();

        Point2D.Double first = polygon.get(0);
        // 通过移动到指定坐标(以双精度指定),将一个点添加到路径中
        generalPath.moveTo(first.x, first.y);
        polygon.remove(0);
        for (Point2D.Double d : polygon) {
            // 通过绘制一条从当前坐标到新指定坐标(以双精度指定)的直线,将一个点添加到路径中。
            generalPath.lineTo(d.x, d.y);
        }
        // 将几何多边形封闭
        generalPath.lineTo(first.x, first.y);
        generalPath.closePath();
        // 测试指定的 Point2D 是否在 Shape 的边界内。
        return generalPath.contains(point);
    }


}

下列工具类出自:https://blog.csdn.net/qq_38567039/article/details/118672509

package cn.com.gome.shop.analyze.backend.service.assistant;

import cn.com.gome.shop.analyze.backend.data.assistant.Point;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GeodeticCalculator;
import org.gavaghan.geodesy.GlobalCoordinates;

import java.awt.geom.Point2D;
import java.util.List;

/**
 * <p>
 * <b>离散点计算工具</b>
 * <p>
 * <pre>
 * 离散点计算工具
 *
 *  y
 *  ↑   ·  ·
 *  │  · ·   ·
 *  │ ·  · ·   ·
 *  │  ·  ·
 * —│————————————→ x
 * </pre>
 */
public class DiscretePointUtil {

    /**
     * <p>
     * <b>查找离散点集中的(min_x, min_Y) (max_x, max_Y)</b>
     * <p>
     * <pre>
     * 查找离散点集中的(min_x, min_Y) (max_x, max_Y)
     * </pre>
     *
     * @param points 离散点集
     * @return [(min_x, min_Y), (max_x, max_Y)]
     */
    public static Point[] calMinMaxDots(final List<Point> points) {
        if (null == points || points.isEmpty()) {
            return null;
        }

        double min_x = points.get(0).getX(), max_x = points.get(0).getX();
        double min_y = points.get(0).getY(), max_y = points.get(0).getY();

        /* 这里存在优化空间,可以使用并行计算 */
        for (Point point : points) {
            if (min_x > point.getX()) {
                min_x = point.getX();
            }

            if (max_x < point.getX()) {
                max_x = point.getX();
            }

            if (min_y > point.getY()) {
                min_y = point.getY();
            }

            if (max_y < point.getY()) {
                max_y = point.getY();
            }
        }

        Point ws = new Point(min_x, min_y);
        Point en = new Point(max_x, max_y);

        return new Point[]{ws, en};
    }

    /**
     * <p>
     * <b>求矩形面积平方根</b>
     * <p>
     * <pre>
     * 以两个点作为矩形的对角线上的两点,计算其面积的平方根
     * </pre>
     *
     * @param ws 西南点
     * @param en 东北点
     * @return 矩形面积平方根
     */
    public static double calRectAreaSquare(Point ws, Point en) {
        if (null == ws || null == en) {
            return .0;
        }

        /* 为防止计算面积时float溢出,先计算各边平方根,再相乘 */
        return Math.sqrt(Math.abs(ws.getX() - en.getX()))
                * Math.sqrt(Math.abs(ws.getY() - en.getY()));
    }

    /**
     * <p>
     * <b>求两点之间的长度 不能用于经纬度</b>
     * <p>
     * <pre>
     * 求两点之间的长度
     * </pre>
     *
     * @param ws 西南点
     * @param en 东北点
     * @return 两点之间的长度
     */
    public static double calLineLen(Point ws, Point en) {
        if (null == ws || null == en) {
            return .0;
        }

        if (ws.equals(en)) {
            return .0;
        }

        double a = Math.abs(ws.getX() - en.getX()); // 直角三角形的直边a
        double b = Math.abs(ws.getY() - en.getY()); // 直角三角形的直边b

        double min = Math.min(a, b); // 短直边
        double max = Math.max(a, b); // 长直边

        /**
         * 为防止计算平方时float溢出,做如下转换
         * √(min²+max²) = √((min/max)²+1) * abs(max)
         */
        double inner = min / max;
        return Math.sqrt(inner * inner + 1.0) * max;
    }

    /**
     * <p>
     * <b>求两点间的中心点</b>
     * <p>
     * <pre>
     * 求两点间的中心点
     * </pre>
     *
     * @param ws 西南点
     * @param en 东北点
     * @return 两点间的中心点
     */
    public static Point calCerter(Point ws, Point en) {
        if (null == ws || null == en) {
            return null;
        }

        return new Point(ws.getX() + (en.getX() - ws.getX()) / 2.0, ws.getY()
                + (en.getY() - ws.getY()) / 2.0);
    }

    /**
     * <p>
     * <b>计算向量角</b>
     * <p>
     * <pre>
     * 计算两点组成的向量与x轴正方向的向量角
     * </pre>
     *
     * @param s 向量起点
     * @param d 向量终点
     * @return 向量角
     */
    public static double angleOf(Point s, Point d) {
        double dist = countPointDistance(new Point2D.Double(s.getX(), s.getY()), new Point2D.Double(d.getX(), d.getY()));

        if (dist <= 0) {
            return .0;
        }

        double x = d.getX() - s.getX(); // 直角三角形的直边a
        double y = d.getY() - s.getY(); // 直角三角形的直边b

        if (y >= 0.) { /* 1 2 象限 */
            return Math.acos(x / dist);
        } else { /* 3 4 象限 */
            return Math.acos(-x / dist) + Math.PI;
        }
    }

    /**
     * <p>
     * <b>修正角度</b>
     * <p>
     * <pre>
     * 修正角度到 [0, 2PI]
     * </pre>
     *
     * @param angle 原始角度
     * @return 修正后的角度
     */
    public static double reviseAngle(double angle) {
        while (angle < 0.) {
            angle += 2 * Math.PI;
        }
        while (angle >= 2 * Math.PI) {
            angle -= 2 * Math.PI;
        }

        return angle;
    }

    /**
     * 计算坐标点之间距离
     * WGS84坐标系
     *
     * @param pointA
     * @param pointB
     * @return
     */
    public static double countPointDistance(Point2D.Double pointA, Point2D.Double pointB) {
        return getDistanceMeter(new GlobalCoordinates(pointA.getY(), pointA.getX()), new GlobalCoordinates(pointB.getY(), pointB.getX()), Ellipsoid.WGS84);
    }

    public static double getDistanceMeter(GlobalCoordinates gpsFrom, GlobalCoordinates gpsTo, Ellipsoid ellipsoid) {
        //创建GeodeticCalculator,调用计算方法,传入坐标系、经纬度用于计算距离
        return new GeodeticCalculator().calculateGeodeticCurve(ellipsoid, gpsFrom, gpsTo).getEllipsoidalDistance();
    }
}
package cn.com.gome.shop.analyze.backend.service.assistant;

import cn.com.gome.shop.analyze.backend.data.assistant.Point;
import cn.com.gome.shop.analyze.backend.data.assistant.ShopSalesStreetPoint;

import java.util.*;

/**
 * <p>
 * <b>最小(凸)包围边界查找</b>
 * <p>
 * <pre>
 * 最小(凸)包围边界查找
 *
 * Minimum Bounding Polygon (Convex Hull; Smallest Enclosing A Set of Points)
 * <b><a href="http://alienryderflex.com/smallest_enclosing_polygon/">©2009 Darel Rex Finley.</a></b>
 *
 *  y
 *  ↑   ·  ·
 *  │  · ·   ·
 *  │ ·  · ·   ·
 *  │  ·  ·
 * —│————————————→ x
 *
 * </pre>
 */
public class MinimumBoundingPolygon {

    public static LinkedList<ShopSalesStreetPoint> findSmallestPolygon(List<ShopSalesStreetPoint> ps) {
        if (null == ps || ps.isEmpty()) {
            return null;
        }

        //查找起始点(保证y最大的情况下、尽量使x最小的点)
        ShopSalesStreetPoint corner = findStartPoint(ps);
        if (null == corner) {
            return null;
        }

        double minAngleDif, oldAngle = 2 * Math.PI;
        LinkedList<ShopSalesStreetPoint> bound = new LinkedList<>();
        do {
            minAngleDif = 2 * Math.PI;

            bound.add(corner);

            ShopSalesStreetPoint nextPoint = corner;
            double nextAngle = oldAngle;
            for (ShopSalesStreetPoint p : ps) {
                if (p.isFounded()) { // 已被加入边界链表的点
                    continue;
                }

                if (p.equals(corner)) { // 重合点
                    /*if (!p.equals(bound.getFirst())) {
                        p.founded = true;
                    }*/
                    continue;
                }

                double currAngle = DiscretePointUtil.angleOf(new Point(corner.getX(), corner.getY()), new Point(p.getX(), p.getY())); /* 当前向量与x轴正方向的夹角 */
                double angleDif = DiscretePointUtil.reviseAngle(oldAngle - currAngle); /* 两条向量之间的夹角(顺时针旋转的夹角) */

                if (angleDif < minAngleDif) {
                    minAngleDif = angleDif;
                    nextPoint = p;
                    nextAngle = currAngle;
                }
            }

            oldAngle = nextAngle;
            corner = nextPoint;
            corner.setFounded(true);
        } while (!corner.equals(bound.getFirst())); /* 判断边界是否闭合 */

        return bound;
    }

    /**
     * 查找起始点(保证y最大的情况下、尽量使x最小的点)
     */
    private static ShopSalesStreetPoint findStartPoint(List<ShopSalesStreetPoint> ps) {
        if (null == ps || ps.isEmpty()) {
            return null;
        }

        ShopSalesStreetPoint p = ps.get(0);
        ListIterator<ShopSalesStreetPoint> iter = ps.listIterator();

        while (iter.hasNext()) {
            ShopSalesStreetPoint point = iter.next();
            if (point.getY() > p.getY() || (point.getY() == p.getY() && point.getX() < p.getX())) { /* 找到最靠上靠左的点 */
                p = point;
            }
        }

        return p;
    }

    private static double cal_cross_product(Point A, Point B, Point C) {
        double AB[] = {B.getX() - A.getX(), B.getY() - A.getY()};
        double AC[] = {C.getX() - A.getX(), C.getY() - A.getY()};
        return AB[0] * AC[1] - AB[1] * AC[0];
    }

    /**
     * 验证点位是否为凸多边形
     *
     * @param points
     * @return
     */
    public static boolean isConvex(List<Point> points) {
        double flag = 0;
        int n = points.size();
        for (int i = 0; i < n; i++) {
            //cur > 0 表示points是按逆时针输出的;cur< 0, 顺时针
            Double cur = cal_cross_product(points.get(i), points.get((i + 1) % n), points.get((i + 2) % n));
            if (cur != 0) {
                //说明异号, 说明有个角大于180度
                if (cur * flag < 0) {
                    return false;
                } else {
                    flag = cur;
                }
            }
        }
        return true;
    }

    public static void main(String[] args) {
        //交道口街道
        Double lng = 116.400978;
        Double lat = 39.93576;
        //东直门
        Double lng1 = 116.441826;
        Double lat1 = 39.930855;
        //龙潭街道
        Double lng2 = 116.436783;
        Double lat2 = 39.887241;
        //体育馆路街道
        Double lng3 = 116.422462;
        Double lat3 = 39.88694;

        //东四街道
        Double lng4 = 116.423988;
        Double lat4 = 39.930332;
        List<Point> pointList = new ArrayList<>();
        pointList.add(new Point(lng, lat));
        pointList.add(new Point(lng1, lat1));
        pointList.add(new Point(lng2, lat2));
        pointList.add(new Point(lng3, lat3));
        pointList.add(new Point(lng4, lat4));
        long start = new Date().getTime();
        boolean convex = isConvex(pointList);
        long end = new Date().getTime();
        System.out.println(convex);
        System.out.println("执行时间:" + (start - end));
    }
}

使用的对象类如下
数据源对象

package cn.com.gome.shop.analyze.backend.data.assistant;

import java.io.Serializable;
import lombok.Data;

/**
 * dwr_store_town_sales_info
 * @author 
 */
@Data
public class DwrStoreTownSalesInfo implements Serializable {
    /**
     * 门店编码
     */
    private String storeCode;

    /**
     * 一级编码
     */
    private String firstCode;

    /**
     * 一级区域
     */
    private String firstArea;

    /**
     * 二级编码
     */
    private String secondCode;

    /**
     * 二级区域
     */
    private String secondArea;

    /**
     * 三级编码
     */
    private String thirdCode;

    /**
     * 三级区域
     */
    private String thirdArea;

    /**
     * 四级编码
     */
    private String fouthCode;

    /**
     * 四级区域
     */
    private String fouthArea;

    /**
     * 是否门店内数据:1是,0否
     */
    private Integer isStore;

    /**
     * 订单用户数
     */
    private Double orderUserNum;

    /**
     * 销量
     */
    private Double salesNum;

    /**
     * 销售额
     */
    private Double salesAmt;

    /**
     * 经度
     */
    private Double x;
    /**
     * 纬度
     */
    private Double y;

    /**
     * 数据统计同步时间
     */
    private String dt;

    private static final long serialVersionUID = 1L;
}

计算所需对象

package cn.com.gome.shop.analyze.backend.data.assistant;

import lombok.Data;

import java.math.BigDecimal;
import java.util.Objects;

/**
 * @author hanhao
 */
@Data
public class ShopSalesStreetPoint {
    public ShopSalesStreetPoint() {
    }

    public ShopSalesStreetPoint(double x, double y) {
        this.x = x;
        this.y = y;
    }

    /**
     * x坐标
     */
    private double x;

    /**
     * y坐标
     */
    private double y;

    /**
     * 边界查找算法中 是否被找到
     */
    boolean founded = false;

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public boolean isFounded() {
        return founded;
    }

    public void setFounded(boolean founded) {
        this.founded = founded;
    }
    /** Constructor Getters & Setters */

    /**
     * 计算值,具体内容可配置
     */
    private BigDecimal value;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ShopSalesStreetPoint that = (ShopSalesStreetPoint) o;
        return Objects.equals(getX(), that.getX()) &&
                Objects.equals(getY(), that.getY());
    }

}

离散点

package cn.com.gome.shop.analyze.backend.data.assistant;

import lombok.Data;

import java.io.Serializable;

/**
 * <p>
 * <b>离散点</b>
 * <p>
 * <pre>
 * 离散点
 * </pre>
 *
 */
public class Point implements Serializable {
    public Point() {
    }

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    /**
     * x坐标
     */
    private double x;

    /**
     * y坐标
     */
    private double y;

    /**
     * 边界查找算法中 是否被找到
     */
    boolean founded = false;

    public double getX() {
        return x;
    }

    public void setX(double x) {
        this.x = x;
    }

    public double getY() {
        return y;
    }

    public void setY(double y) {
        this.y = y;
    }

    public boolean isFounded() {
        return founded;
    }

    public void setFounded(boolean founded) {
        this.founded = founded;
    }
    /** Constructor Getters & Setters */

}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值