Polygon计算每一个角的角度

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
Polygon计算每一个角的角度_第1张图片
那么每一个角的角度构造的直线为

  • 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;

/**
 * 

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(); } } }

AWT 中左上角为原点(0,0) 所以旋转
Polygon计算每一个角的角度_第2张图片

Polygon计算每一个角的角度_第3张图片

源码

本文代码及可视化代码均放在 gitee 码云上 欢迎star & fork

你可能感兴趣的:(map,JAVA)