显然,本算法的抽稀精度也与阈值相关,阈值越大,简化程度越大,点减少的越多,反之,化简程度越低,点保留的越多,形状也越趋于原曲线。
Point.java
package com.mapbar.jts; /** * Class Point.java * Description * Company mapbar * author Chenll E-mail: [email protected] * Version 1.0 * Date 2012-6-28 下午05:51:09 */ public class Point { /** * 点的X坐标 */ private double x = 0; /** * 点的Y坐标 */ private double y = 0; /** * 点所属的曲线的索引 */ private int index = 0; public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; } public int getIndex() { return index; } public void setIndex(int index) { this.index = index; } /** * 点数据的构造方法 * * @param x * 点的X坐标 * @param y * 点的Y坐标 * @param index点所属的曲线的索引 */ public Point(double x, double y, int index) { this.x = x; this.y = y; this.index = index; } }
package com.mapbar.jts; import java.util.ArrayList; import java.util.List; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; /** * * Class Douglas.java * * Description * * Company mapbar * * author Chenll E-mail: [email protected] * * Version 1.0 * * Date 2012-6-28 下午02:53:58 */ public class Douglas { /** * 存储采样点数据的链表 */ public List<Point> points = new ArrayList<Point>(); /** * 控制数据压缩精度的极差 */ private static final double D = 1; private WKTReader reader; /** * 构造Geometry * * @param str * @return */ public Geometry buildGeo(String str) { try { if (reader == null) { reader = new WKTReader(); } return reader.read(str); } catch (ParseException e) { throw new RuntimeException("buildGeometry Error", e); } } /** * 读取采样点 */ public void readPoint() { Geometry g = buildGeo("LINESTRING (1 4,2 3,4 2,6 6,7 7,8 6,9 5,10 10)"); Coordinate[] coords = g.getCoordinates(); for (int i = 0; i < coords.length; i++) { Point p = new Point(coords[i].x, coords[i].y, i); points.add(p); } } /** * 对矢量曲线进行压缩 * * @param from * 曲线的起始点 * @param to * 曲线的终止点 */ public void compress(Point from, Point to) { /** * 压缩算法的开关量 */ boolean switchvalue = false; /** * 由起始点和终止点构成的直线方程一般式的系数 */ System.out.println(from.getY()); System.out.println(to.getY()); double A = (from.getY() - to.getY()) / Math.sqrt(Math.pow((from.getY() - to.getY()), 2) + Math.pow((from.getX() - to.getX()), 2)); /** * 由起始点和终止点构成的直线方程一般式的系数 */ double B = (to.getX() - from.getX()) / Math.sqrt(Math.pow((from.getY() - to.getY()), 2) + Math.pow((from.getX() - to.getX()), 2)); /** * 由起始点和终止点构成的直线方程一般式的系数 */ double C = (from.getX() * to.getY() - to.getX() * from.getY()) / Math.sqrt(Math.pow((from.getY() - to.getY()), 2) + Math.pow((from.getX() - to.getX()), 2)); double d = 0; double dmax = 0; int m = points.indexOf(from); int n = points.indexOf(to); if (n == m + 1) return; Point middle = null; List<Double> distance = new ArrayList<Double>(); for (int i = m + 1; i < n; i++) { d = Math.abs(A * (points.get(i).getX()) + B * (points.get(i).getY()) + C) / Math.sqrt(Math.pow(A, 2) + Math.pow(B, 2)); distance.add(d); } dmax = distance.get(0); for (int j = 1; j < distance.size(); j++) { if (distance.get(j) > dmax) dmax = distance.get(j); } if (dmax > D) switchvalue = true; else switchvalue = false; if (!switchvalue) { // 删除Points(m,n)内的坐标 for (int i = m + 1; i < n; i++) { points.get(i).setIndex(-1); } } else { for (int i = m + 1; i < n; i++) { if ((Math.abs(A * (points.get(i).getX()) + B * (points.get(i).getY()) + C) / Math.sqrt(Math.pow(A, 2) + Math.pow(B, 2)) == dmax)) middle = points.get(i); } compress(from, middle); compress(middle, to); } } public static void main(String[] args) { Douglas d = new Douglas(); d.readPoint(); d.compress(d.points.get(0), d.points.get(d.points.size() - 1)); for (int i = 0; i < d.points.size(); i++) { Point p = d.points.get(i); if (p.getIndex() > -1) { System.out.print(p.getX() + " " + p.getY() + ","); } } } }
输出结果:1.0 4.0,4.0 2.0,7.0 7.0,9.0 5.0,10.0 10.0,其中2 3,6 6,8 6两个坐标被抽稀掉了。
示意图: