当前位置:网站首页>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
边栏推荐
- 吞吐?带宽?傻傻分不清楚
- 【数据库和SQL学习笔记】10.(T-SQL语言)函数、存储过程、触发器
- 读论文-Cycle GAN
- flink yarn-session的两种使用方式
- Service
- CH32V307 LwIP移植使用
- 基于STM32F407的一个温度传感器报警系统(用的是DS18B20温度传感器,4针0.96寸OLED显示屏,并且附带日期显示)
- 【论文精读】Rich Feature Hierarchies for Accurate Object Detection and Semantic Segmentation(R-CNN)
- 用GAN的方法来进行图片匹配!休斯顿大学提出用于文本图像匹配的对抗表示学习,消除模态差异!
- [Database and SQL study notes] 10. (T-SQL language) functions, stored procedures, triggers
猜你喜欢
![[Intensive reading of the paper] R-CNN's Bounding box regression problem is detailed](/img/ef/a058ec08bd0a6313e3610a4ebc9685.png)
[Intensive reading of the paper] R-CNN's Bounding box regression problem is detailed

如何停止flink job

Mysql-连接https域名的Mysql数据源踩的坑

The University of Göttingen proposed CLIPSeg, a model that can perform three segmentation tasks at the same time

ECCV2022 | RU & Google propose zero-shot object detection with CLIP!

读论文- pix2pix

伪RTOS-ProroThread在CH573芯片上的移植

【数据库和SQL学习笔记】3.数据操纵语言(DML)、SELECT查询初阶用法

flink部署操作-flink on yarn集群安装部署
![[Database and SQL study notes] 10. (T-SQL language) functions, stored procedures, triggers](/img/b9/06b90160c962a25a3cc44731afb6dc.png)
[Database and SQL study notes] 10. (T-SQL language) functions, stored procedures, triggers
随机推荐
6k+ star,面向小白的深度学习代码库!一行代码实现所有Attention机制!
基于STM32F4的FFT+测频率幅值相位差,波形显示,示波器,时域频域分析相关工程
如何编写一个优雅的Shell脚本(二)
【Multisim仿真】直流稳压电源设计报告
「实用」运维新手一定不能错过的17 个技巧
盘点关于发顶会顶刊论文,你需要知道写作上的这些事情!
八、请求处理之自定义类型参数绑定原理
MySQL
【Shell编程】第一章:子串
基于Flink CDC实现实时数据采集(二)-Source接口实现
原来何恺明提出的MAE还是一种数据增强
如何编写一个优雅的Shell脚本(三)
PID详解
CVPR最佳论文得主清华黄高团队提出首篇动态网络综述
六步搞定子网划分
华科提出首个用于伪装实例分割的一阶段框架OSFormer
Redis设计与实现(第二部分):单机数据库的实现
OSPF网络类型
Service
Tensorflow steps on the pit notes and records various errors and solutions