diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c41cc9e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index a4efda8..119df35 100644
--- a/pom.xml
+++ b/pom.xml
@@ -103,6 +103,21 @@
gt-geotiff
${geotools.version}
+
+ org.geotools
+ gt-geojson
+ ${geotools.version}
+
+
+ org.geotools
+ gt-geometry
+ 24.0
+
+
+ com.alibaba
+ fastjson
+ 1.2.47
+
org.gdal
@@ -111,6 +126,14 @@
system
${project.basedir}/${gdal.binddir}/gdal-3.8.4.jar
+
+ opencv
+ opencv-490
+ opencv-490
+ system
+ true
+ ${project.basedir}/src/main/resources/opencv/opencv-490.jar
+
junit
junit
diff --git a/src/main/java/org/example/alpha/AlphaShape.java b/src/main/java/org/example/alpha/AlphaShape.java
new file mode 100644
index 0000000..a612f7f
--- /dev/null
+++ b/src/main/java/org/example/alpha/AlphaShape.java
@@ -0,0 +1,134 @@
+package org.example.alpha;
+
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.LineString;
+import org.locationtech.jts.geom.Polygon;
+import org.locationtech.jts.operation.polygonize.Polygonizer;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Alpha Shapes提取离散点凹边轮廓线(java实现)
+ */
+public class AlphaShape {
+
+ private double radius;
+
+ private int sortCount = 0;
+ //轮廓探寻的圆半径
+ public AlphaShape(double radius) {
+ this.radius = radius;
+ }
+
+ public List> boundaryPoints(List points) {
+
+ if (points == null || points.size() == 0) {
+ return null;
+ }
+ //编号
+ int no = 1;
+ for (Vector2D point : points) {
+ point.setId(no);
+ no++;
+ }
+
+ List boundary = new ArrayList<>();
+ List lines = new ArrayList<>();
+ int edgeNo = 1;
+ for (int i = 0; i < points.size(); i++) {
+
+ // k从i+1开始,减少重复计算
+ for (int k = i + 1; k < points.size(); k++) {
+ // 跳过距离大于直径的情况
+ if (points.get(i).distanceToPoint(points.get(k)) > 2 * radius) {
+ continue;
+ }
+ // 两个圆心
+ Vector2D c1, c2;
+ // 线段中点
+ Vector2D center = points.get(i).add(points.get(k)).center();
+ // 方向向量 d = (x,y)
+ Vector2D dir = points.get(i).subtract(points.get(k));
+ // 垂直向量 n = (a,b) a*dir.x+b*dir.y = 0; a = -(b*dir.y/dir.x)
+ Vector2D normal = new Vector2D();
+ // 因为未知数有两个,随便给y附一个值5。
+ normal.setY(5);
+
+ if (dir.getX() != 0) {
+ normal.setX(-(normal.getY() * dir.getY()) / dir.getX());
+ } else {
+ // 如果方向平行于y轴
+ normal.setX(1);
+ normal.setY(0);
+ }
+ // 法向量单位化
+ normal.normalize();
+
+ double len = Math.sqrt(radius * radius - (0.25 * dir.length() * dir.length()));
+ c1 = center.add(normal.multiply(len));
+ c2 = center.subtract(normal.multiply(len));
+
+ // b1、b2记录是否在圆C1、C2中找到其他点。
+ boolean b1 = false, b2 = false;
+ for (int m = 0; m < points.size(); m++) {
+ if (m == i || m == k) {
+ continue;
+ }
+ if (b1 != true && points.get(m).distanceToPoint(c1) < radius) {
+ b1 = true;
+ }
+ if (b2 != true && points.get(m).distanceToPoint(c2) < radius) {
+ b2 = true;
+ }
+ // 如果都有内部点,不必再继续检查了
+ if (b1 == true && b2 == true) {
+ break;
+ }
+ }
+
+ if (b1 != true || b2 != true) {
+ Edge edge = new Edge();
+ edge.setId(edgeNo);
+ edge.setA(points.get(i));
+ edge.setB(points.get(k));
+ edgeNo++;
+ boundary.add(points.get(i));
+ boundary.add(points.get(k));
+ lines.add(edge);
+ }
+ }
+ }
+
+ if (lines.size() <= 1) {
+ return Collections.emptyList();
+ }
+
+ List> polygonPoints = new ArrayList<>();
+ Polygonizer polygonizer = new Polygonizer();
+ List lineStrings = new ArrayList<>(lines.size());
+ for (Edge line : lines) {
+ Coordinate A = new Coordinate(line.getA().getX(), line.getA().getY());
+ Coordinate B = new Coordinate(line.getB().getX(), line.getB().getY());
+ LineString lineString = new GeometryFactory().createLineString(new Coordinate[]{A,B});
+ lineStrings.add(lineString);
+ }
+ //线条多边形化
+ polygonizer.add(lineStrings);
+ Collection polygonList=polygonizer.getPolygons();
+ for (Object polObj : polygonList) {
+ Polygon polygon = (Polygon) polObj;
+ Coordinate[] coordinates=polygon.getCoordinates();
+ List vector2DS = new ArrayList<>();
+ for (Coordinate coordinate : coordinates) {
+ Vector2D vector2D = new Vector2D(coordinate.x, coordinate.y);
+ vector2DS.add(vector2D);
+ }
+ polygonPoints.add(vector2DS);
+ }
+ return polygonPoints;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/example/alpha/Edge.java b/src/main/java/org/example/alpha/Edge.java
new file mode 100644
index 0000000..7d8c20e
--- /dev/null
+++ b/src/main/java/org/example/alpha/Edge.java
@@ -0,0 +1,83 @@
+package org.example.alpha;
+
+public class Edge {
+
+ private int id;
+
+ private Vector2D a;
+
+ private Vector2D b;
+
+ private Edge next;
+
+ private boolean hasReversal=false;
+
+ private boolean hasNext=false;
+
+ public Edge() {
+
+ }
+
+ public Edge(Vector2D a, Vector2D b) {
+ this.a = a;
+ this.b = b;
+ }
+
+ public Edge(int id,Vector2D a, Vector2D b) {
+ this.id = id;
+ this.a = a;
+ this.b = b;
+ }
+
+ public void reversal() {
+ Vector2D temp = this.a;
+ this.a = this.b;
+ this.b = temp;
+ hasReversal = true;
+ }
+
+ public Vector2D getA() {
+ return a;
+ }
+
+ public void setA(Vector2D a) {
+ this.a = a;
+ }
+
+ public Vector2D getB() {
+ return b;
+ }
+
+ public void setB(Vector2D b) {
+ this.b = b;
+ }
+
+ public Edge getNext() {
+ return next;
+ }
+
+ public void setNext(Edge next) {
+ if (next != null) {
+ this.next = next;
+ hasNext = true;
+ }
+
+ }
+
+
+ public boolean hasReversal() {
+ return this.hasReversal;
+ }
+
+ public boolean hasNext() {
+ return this.hasNext;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/example/alpha/Vector2D.java b/src/main/java/org/example/alpha/Vector2D.java
new file mode 100644
index 0000000..a547aed
--- /dev/null
+++ b/src/main/java/org/example/alpha/Vector2D.java
@@ -0,0 +1,226 @@
+package org.example.alpha;
+
+import java.util.Objects;
+
+public class Vector2D {
+
+ private int id;
+ private double x;
+ private double y;
+ private double distance;
+ private Vector2D next;
+
+ private double bottomHeight;
+ private double topHeight;
+ private String index;
+
+ public Vector2D() {
+ x = 0;
+ y = 0;
+ }
+
+ public Vector2D(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ //获取弧度
+ public double radian() {
+ return Math.atan2(y, x);
+ }
+
+ //获取角度
+ public double angle() {
+ return radian() / Math.PI * 180;
+ }
+
+ public Vector2D clone() {
+ return new Vector2D(x, y);
+ }
+
+ public double length() {
+ return Math.sqrt(getLengthSQ());
+ }
+
+ public double getLengthSQ() {
+ return x * x + y * y;
+ }
+
+ //向量置零
+ public Vector2D Zero() {
+ x = 0;
+ y = 0;
+ return this;
+ }
+
+ public boolean isZero() {
+ return x == 0 && y == 0;
+ }
+
+ //向量的长度设置为我们期待的value
+ public void setLength(double value) {
+ double _angle = angle();
+ x = Math.cos(_angle) * value;
+ y = Math.sin(_angle) * value;
+ }
+
+ //向量的标准化(方向不变,长度为1)
+ public Vector2D normalize() {
+ double length = length();
+ x = x / length;
+ y = y / length;
+ return this;
+ }
+
+ //是否已经标准化
+ public boolean isNormalized() {
+ return length() == 1.0;
+ }
+
+ //向量的方向翻转
+ public Vector2D reverse() {
+ x = -x;
+ y = -y;
+ return this;
+ }
+
+ //2个向量的数量积(点积)
+ public double dotProduct(Vector2D v) {
+ return x * v.x + y * v.y;
+ }
+
+ //2个向量的向量积(叉积)
+ public double crossProduct(Vector2D v) {
+ return x * v.y - y * v.x;
+ }
+
+ //计算2个向量的夹角弧度
+ //参考点积公式:v1 * v2 = cos * |v1| *|v2|
+ public static double radianBetween(Vector2D v1, Vector2D v2) {
+ if (!v1.isNormalized()) v1 = v1.clone().normalize(); // |v1| = 1
+ if (!v2.isNormalized()) v2 = v2.clone().normalize(); // |v2| = 1
+ return Math.acos(v1.dotProduct(v2));
+ }
+
+ //弧度 = 角度乘以PI后再除以180、 推理可得弧度换算角度的公式
+ //弧度转角度
+ public static double radian2Angle(double radian) {
+ return radian / Math.PI * 180;
+ }
+
+ //向量加
+ public Vector2D add(Vector2D v) {
+ return new Vector2D(x + v.x, y + v.y);
+ }
+
+ //向量减
+ public Vector2D subtract(Vector2D v) {
+ return new Vector2D(x - v.x, y - v.y);
+ }
+
+ //向量乘
+ public Vector2D multiply(double value) {
+ return new Vector2D(x * value, y * value);
+ }
+
+ //向量除
+ public Vector2D divide(double value) {
+ return new Vector2D(x / value, y / value);
+ }
+
+
+ public double distanceToPoint(Vector2D point) {
+ double dx = this.x - point.getX();
+ double dy = this.y - point.getY();
+ double distance = Math.sqrt(dx * dx + dy * dy);
+ return Math.abs(distance);
+ }
+
+ public double getX() {
+ return x;
+ }
+
+ public double getY() {
+ return y;
+ }
+
+ public void setX(double x) {
+ this.x = x;
+ }
+
+ public void setY(double y) {
+ this.y = y;
+ }
+
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ public double getDistance() {
+ return distance;
+ }
+
+ public void setDistance(double distance) {
+ this.distance = distance;
+ }
+
+ public Vector2D next() {
+ return next;
+ }
+
+ public void setNext(Vector2D next) {
+ this.next = next;
+ }
+
+ public double getBottomHeight() {
+ return bottomHeight;
+ }
+
+ public double getTopHeight() {
+ return topHeight;
+ }
+
+ public void setBottomHeight(double bottomHeight) {
+ this.bottomHeight = bottomHeight;
+ }
+
+ public void setTopHeight(double topHeight) {
+ this.topHeight = topHeight;
+ }
+
+ public String getIndex() {
+ return index;
+ }
+
+ public void setIndex(String index) {
+ this.index = index;
+ }
+
+ /**
+ * 线段中点
+ *
+ * @return
+ */
+ public Vector2D center() {
+ return new Vector2D(getX() * 0.5, getY() * 0.5);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ Vector2D vector2D = (Vector2D) o;
+ return id == vector2D.id &&
+ Double.compare(vector2D.x, x) == 0 &&
+ Double.compare(vector2D.y, y) == 0;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(x, y);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/example/controller/RingGridController.java b/src/main/java/org/example/controller/RingGridController.java
new file mode 100644
index 0000000..39fd43a
--- /dev/null
+++ b/src/main/java/org/example/controller/RingGridController.java
@@ -0,0 +1,76 @@
+package org.example.controller;
+
+import com.alibaba.fastjson.JSONArray;
+import org.example.dto.FillCutDto;
+import org.example.service.RingGridService;
+import org.example.test.CreateRingGridFix;
+import org.example.utils.CommonResult;
+import org.geotools.api.geometry.Position;
+import org.geotools.api.referencing.crs.CoordinateReferenceSystem;
+import org.geotools.coverage.grid.GridCoordinates2D;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridGeometry2D;
+import org.geotools.coverage.processing.Operations;
+import org.geotools.gce.geotiff.GeoTiffReader;
+import org.geotools.geometry.Position2D;
+import org.geotools.referencing.CRS;
+import org.geotools.util.factory.Hints;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Point;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.Mapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@RestController
+public class RingGridController {
+ @Autowired
+ public RingGridService ringGridService;
+
+ @RequestMapping("/fillcut")
+ public CommonResult