POLYGON ((350 100, 450 450, 150 400, 100 200, 350 100), (200 300, 350 350, 300 200, 200 300))
Coordinate[] coordinates = geometry.getCoordinates();
获取的结果为
[(350.0, 100.0, NaN), (450.0, 450.0, NaN), (150.0, 400.0, NaN), (100.0, 200.0, NaN), (350.0, 100.0, NaN)]
顺序为 节点0 , 节点1 , 节点2 , 节点3 , 节点0 最终回到 节点0
那么每一个角的角度构造的直线为
根据以上的直线计算流程即可获得每个角度
package com.huifer.planar.aset.entity;
import com.huifer.planar.aset.algo.impl.PolygonAngleCore.PointF;
import java.util.HashMap;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.locationtech.jts.geom.Polygon;
/**
* Title : PolygonAngleResult
* Description : polygon 角度计算结果
*
* @author huifer
* @date 2019-01-28
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class PolygonAngleResult {
private List<HashMap<PointF, Double>> polygonAngles;
private Polygon polygon;
}
package com.huifer.planar.aset.algo.impl;
import com.huifer.planar.aset.algo.PolygonAngleInterface;
import com.huifer.planar.aset.entity.PolygonAngleResult;
import com.huifer.planar.aset.utils.shptools.overlay.Operation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
/**
* Title : PolygonAngleCore
* Description : polygon 计算角度
*
* @author huifer
* @date 2019-01-28
*/
public class PolygonAngleCore implements PolygonAngleInterface {
/**
* 计算夹角
*
* @param o 基准点 两条直线共有点
* @param s 起点
* @param e 终点
* @return 角度
*/
public static double angle(PointF o, PointF s,
PointF e) {
double cosfi = 0, fi = 0, norm = 0;
double dsx = s.x - o.x;
double dsy = s.y - o.y;
double dex = e.x - o.x;
double dey = e.y - o.y;
cosfi = dsx * dex + dsy * dey;
norm = (dsx * dsx + dsy * dsy) * (dex * dex + dey * dey);
cosfi /= Math.sqrt(norm);
if (cosfi >= 1.0) {
return 0;
}
if (cosfi <= -1.0) {
return Math.PI;
}
fi = Math.acos(cosfi);
if (180 * fi / Math.PI < 180) {
return 180 * fi / Math.PI;
} else {
return 360 - 180 * fi / Math.PI;
}
}
/**
* 节点 1,2 | 2,3 节点 2,3 | 3,4 节点 4,1 | 1,2 计算角度
*
* @param coordinates 节点坐标值
* @return 角度列表
*/
private static HashMap<PointF, Double> calcAngle(Coordinate[] coordinates) {
List<Double> angles = new ArrayList<>();
HashMap<PointF, Double> rs = new HashMap<>();
for (int i = 0; i < coordinates.length; i++) {
if (i + 2 < coordinates.length) {
// 基准点
PointF o = new PointF(coordinates[i + 1].x, coordinates[i + 1].y);
// 起点
PointF s = new PointF(coordinates[i].x, coordinates[i].y);
// 终点
PointF e = new PointF(coordinates[i + 2].x, coordinates[i + 2].y);
double angle = angle(o, s, e);
angles.add(angle);
rs.put(o, angle);
}
if (i == coordinates.length - 1) {
PointF o = new PointF(coordinates[0].x, coordinates[0].y);
PointF s = new PointF(coordinates[coordinates.length - 2].x,
coordinates[coordinates.length - 2].y);
PointF e = new PointF(coordinates[1].x, coordinates[1].y);
double angle = angle(o, s, e);
angles.add(angle);
rs.put(o, angle);
}
}
return rs;
}
/**
* polygon计算角度核心
*
* @param wkt polygonWKT描述
* @return {@link PolygonAngleResult}
* @throws ParseException wkt格式化异常
*/
private static PolygonAngleResult polygonWktAngleCore(String wkt)
throws ParseException {
Operation op = new Operation();
GeometryFactory gFactory = new GeometryFactory();
Polygon polygon = op.createPolygonByWKT(wkt);
List<HashMap<PointF, Double>> polygonAngles = new ArrayList<>();
List<LineString> ls = new ArrayList<>();
PolygonAngleResult polygonAngleResult = new PolygonAngleResult();
Geometry geometry = null;
// 是否有环形
if (polygon.getNumInteriorRing() == 0) {
LineString exteriorRing = polygon.getExteriorRing();
geometry = gFactory.createMultiLineString(new LineString[]{exteriorRing});
Coordinate[] coordinates = geometry.getCoordinates();
HashMap<PointF, Double> doubles = calcAngle(coordinates);
polygonAngles.add(doubles);
polygonAngleResult.setPolygon(polygon);
polygonAngleResult.setPolygonAngles(polygonAngles);
} else {
geometry = polygon.getBoundary();
// geometry 数量
int dimension = geometry.getDimension();
for (int i = 0; i <= dimension; i++) {
Geometry line = geometry.getGeometryN(i);
ls.add((LineString) line);
Coordinate[] coordinates = line.getCoordinates();
HashMap<PointF, Double> doubles = calcAngle(coordinates);
polygonAngles.add(doubles);
}
polygonAngleResult.setPolygon(polygon);
polygonAngleResult.setPolygonAngles(polygonAngles);
}
return polygonAngleResult;
}
@Override
public PolygonAngleResult polygonWktAngle(String wkt) throws ParseException {
PolygonAngleResult polygonAngleResult = polygonWktAngleCore(wkt);
return polygonAngleResult;
}
/**
* 计算两条直线之间夹角的点类
*/
@EqualsAndHashCode
@Data
public static class PointF {
double x;
double y;
public PointF() {
}
public PointF(double x, double y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("{");
sb.append("\"x\":")
.append(x);
sb.append(",\"y\":")
.append(y);
sb.append('}');
return sb.toString();
}
}
}
package com.huifer.planar.aset.view;
import com.huifer.planar.aset.algo.PolygonAngleInterface;
import com.huifer.planar.aset.algo.impl.PolygonAngleCore;
import com.huifer.planar.aset.algo.impl.PolygonAngleCore.PointF;
import com.huifer.planar.aset.entity.PolygonAngleResult;
import com.huifer.planar.aset.view.base.BaseFrame;
import com.huifer.planar.aset.view.base.FrameContext;
import com.huifer.planar.aset.view.base.ViewHelper;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.util.HashMap;
import java.util.List;
import org.locationtech.jts.awt.ShapeWriter;
import org.locationtech.jts.geom.Polygon;
import org.locationtech.jts.io.ParseException;
/**
* Title : PolygonAngleView
* Description :PolygonAngleView
*
* @author huifer
* @date 2019-01-28
*/
public class PolygonAngleView extends FrameContext {
public static void main(String[] args) {
PolygonAngleView polygonAngleView = new PolygonAngleView();
BaseFrame frame = new BaseFrame(polygonAngleView);
frame.run();
}
@Override
public void drawing(Graphics g) throws ParseException {
// String wkt = "POLYGON ((350 100, 450 450, 150 400, 100 200, 350 100), (200 300, 350 350, 300 200, 200 300))";
String wkt = "POLYGON ((350 100, 450 450, 150 400, 100 200, 350 100))";
ShapeWriter sw = new ShapeWriter();
PolygonAngleInterface polygonAngleInterface = new PolygonAngleCore();
PolygonAngleResult polygonAngleResult = polygonAngleInterface.polygonWktAngle(wkt);
Graphics2D g2d = (Graphics2D) g;
Polygon polygon = polygonAngleResult.getPolygon();
List<HashMap<PointF, Double>> polygonAngles = polygonAngleResult.getPolygonAngles();
// 绘图流程
ViewHelper.setStrokeWidth(g2d, 2);
ViewHelper.setColor(g2d, ViewHelper.BLUE);
Shape polyShape = sw.toShape(polygon);
g2d.draw(polyShape);
ViewHelper.setColor(g2d, ViewHelper.GREEN);
for (HashMap<PointF, Double> angle : polygonAngles) {
angle.forEach(
(k, v) -> {
ViewHelper.drawText(g2d, v.toString(), (int) k.getX(), (int) k.getY());
}
);
}
}
@Override
public void paintComponent(Graphics g) {
try {
drawing(g);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
本文代码及可视化代码均放在 gitee 码云上 欢迎star & fork