当前位置:网站首页>Polygon计算每一个角的角度
Polygon计算每一个角的角度
2022-08-05 05:16:00 【staHuri】
Polygon计算每一个角的角度
主要算法
- Polygon 拆解 (孔型)
- 两条线段之间求角度值
测试数据
- 面数据
POLYGON ((350 100, 450 450, 150 400, 100 200, 350 100), (200 300, 350 350, 300 200, 200 300))
流程注解
- JTS org.locationtech.jts.geom.Geometry 类
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
那么每一个角的角度构造的直线为
- 0,1 - 1,2
- 1,2 - 2,3
- 2,3 - 3,4
- 4/0,3 - 4/0,1
根据以上的直线计算流程即可获得每个角度
代码实现
- 数据结果
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;
/** * <p>Title : PolygonAngleResult </p> * <p>Description : polygon 角度计算结果</p> * * @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;
/** * <p>Title : PolygonAngleCore </p> * <p>Description : polygon 计算角度 </p> * * @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;
/** * <p>Title : PolygonAngleView </p> * <p>Description :PolygonAngleView </p> * * @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();
}
}
}
AWT 中左上角为原点(0,0) 所以旋转
源码
本文代码及可视化代码均放在 gitee 码云上 欢迎star & fork
边栏推荐
猜你喜欢
华科提出首个用于伪装实例分割的一阶段框架OSFormer
The University of Göttingen proposed CLIPSeg, a model that can perform three segmentation tasks at the same time
初识机器学习
MSRA proposes extreme masking model ExtreMA for learning instances and distributed visual representations
flink项目开发-flink的scala shell命令行交互模式开发
PID详解
八、请求处理之自定义类型参数绑定原理
网管日记:故障网络交换机快速替换方法
读论文 - Unpaired Portrait Drawing Generation via Asymmetric Cycle Mapping
十一、拦截器运行原理
随机推荐
【ts】typescript高阶:键值类型及type与interface区别
《基于机器视觉的输电线路交叉点在线测量方法及技术方案》论文笔记
[Database and SQL study notes] 9. (T-SQL language) Define variables, advanced queries, process control (conditions, loops, etc.)
BroadCast Receiver(广播)详解
Detailed explanation of BroadCast Receiver (broadcast)
SharedPreferences and SQlite database
基于STM32F407的一个温度传感器报警系统(用的是DS18B20温度传感器,4针0.96寸OLED显示屏,并且附带日期显示)
十、视图解析原理与源码分析
【22李宏毅机器学习】课程大纲概述
Facial Motion Capture 调研
Web Component-处理数据
原来何恺明提出的MAE还是一种数据增强
Kubernetes常备技能
Redis集群(docker版)——从原理到实战超详细
如何停止flink job
flink项目开发-flink的scala shell命令行交互模式开发
[Intensive reading of the paper] R-CNN's Bounding box regression problem is detailed
Comparison and summary of Tensorflow2 and Pytorch in terms of basic operations of tensor Tensor
Mysql-连接https域名的Mysql数据源踩的坑
【数据库和SQL学习笔记】8.SQL中的视图(view)