Skip to content

Commit

Permalink
Merge pull request #24 from badger3512/master
Browse files Browse the repository at this point in the history
Add precision reducer classes along with associated and dependent classes and tests
  • Loading branch information
moovida authored May 1, 2024
2 parents 818f228 + 1405b94 commit a5098ab
Show file tree
Hide file tree
Showing 54 changed files with 10,229 additions and 260 deletions.
30 changes: 30 additions & 0 deletions lib/dart_jts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,14 @@ part 'src/com/hydrologis/dart_jts/operation/overlay.dart';
part 'src/com/hydrologis/dart_jts/operation/predicate.dart';
part 'src/com/hydrologis/dart_jts/operation/buffer.dart';
part 'src/com/hydrologis/dart_jts/operation/buffer_validate.dart';
part 'src/com/hydrologis/dart_jts/edgegraph/half_edge.dart';
part 'src/com/hydrologis/dart_jts/edgegraph/edge_graph.dart';
part 'src/com/hydrologis/dart_jts/edgegraph/edge_graph_builder.dart';
part 'src/com/hydrologis/dart_jts/edgegraph/mark_half_edge.dart';
part 'src/com/hydrologis/dart_jts/noding/noding.dart';
part 'src/com/hydrologis/dart_jts/noding/fast_noding_validator.dart';
part 'src/com/hydrologis/dart_jts/noding/noding_intersection_finder.dart';
part 'src/com/hydrologis/dart_jts/noding/snap_round.dart';
part 'src/com/hydrologis/dart_jts/math/math.dart';
part 'src/com/hydrologis/dart_jts/geomgraph/geomgraph.dart';
part 'src/com/hydrologis/dart_jts/geomgraph/index.dart';
Expand All @@ -47,6 +54,7 @@ part 'src/com/hydrologis/dart_jts/index/index.dart';
part 'src/com/hydrologis/dart_jts/index/chain.dart';
part 'src/com/hydrologis/dart_jts/index/strtree.dart';
part 'src/com/hydrologis/dart_jts/index/quadtree.dart';
part 'src/com/hydrologis/dart_jts/index/kdtree.dart';
part 'src/com/hydrologis/dart_jts/util/avltree.dart';
part 'src/com/hydrologis/dart_jts/extra.dart';
part 'src/com/hydrologis/dart_jts/addons/geodesy.dart';
Expand All @@ -71,3 +79,25 @@ part 'src/com/hydrologis/dart_jts/simplify/line_segment_index.dart';
part 'src/com/hydrologis/dart_jts/simplify/tagged_line_string_simplifier.dart';
part 'src/com/hydrologis/dart_jts/simplify/vw_simplifier.dart';
part 'src/com/hydrologis/dart_jts/simplify/vw_line_simplifier.dart';
part 'src/com/hydrologis/dart_jts/precision/geometry_precision_reducer.dart';
part 'src/com/hydrologis/dart_jts/precision/pointwise_precision_reducer_transformer.dart';
part 'src/com/hydrologis/dart_jts/precision/precision_reducer_transformer.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_ng.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/intersection_point_builder.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_edge_ring.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_edge.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_mixed_points.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/indexed_point_on_line_locator.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/input_geometry.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_util.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/elevation_model.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_label.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_graph.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/overlay_points.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/line_builder_ng.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/edge_noding_builder.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/ring_clipper.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/line_limiter.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/edge_source_info.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/edge_merger.dart';
part 'src/com/hydrologis/dart_jts/operation/overlayng/maximal_edge_ring_ng.dart';
104 changes: 97 additions & 7 deletions lib/src/com/hydrologis/dart_jts/algorithm/algorithm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,41 @@ class CGAlgorithmsDD {
.signum();
}

/**
* Returns the index of the direction of the point {@code q} relative to
* a vector specified by {@code p1-p2}.
*
* @param p1x the x ordinate of the vector origin point
* @param p1y the y ordinate of the vector origin point
* @param p2x the x ordinate of the vector final point
* @param p2y the y ordinate of the vector final point
* @param qx the x ordinate of the query point
* @param qy the y ordinate of the query point
*
* @return 1 if q is counter-clockwise (left) from p1-p2
* -1 if q is clockwise (right) from p1-p2
* 0 if q is collinear with p1-p2
*/
static int orientationIndexDouble(
double p1x, double p1y, double p2x, double p2y, double qx, double qy) {
// fast filter for orientation index
// avoids use of slow extended-precision arithmetic in many cases
int index = orientationIndexFilterDouble(p1x, p1y, p2x, p2y, qx, qy);
if (index <= 1) return index;

// normalize coordinates
DD dx1 = DD.valueOf(p2x).selfAdd(-p1x);
DD dy1 = DD.valueOf(p2y).selfAdd(-p1y);
DD dx2 = DD.valueOf(qx).selfAdd(-p2x);
DD dy2 = DD.valueOf(qy).selfAdd(-p2y);

// sign of determinant - unrolled for performance
return dx1
.selfMultiplyDD(dy2)
.selfSubtractDD(dy1.selfMultiplyDD(dx2))
.signum();
}

/// Computes the sign of the determinant of the 2x2 matrix
/// with the given entries.
///
Expand Down Expand Up @@ -117,6 +152,61 @@ class CGAlgorithmsDD {
return 2;
}

/**
* A filter for computing the orientation index of three coordinates.
* <p>
* If the orientation can be computed safely using standard DP
* arithmetic, this routine returns the orientation index.
* Otherwise, a value i > 1 is returned.
* In this case the orientation index must
* be computed using some other more robust method.
* The filter is fast to compute, so can be used to
* avoid the use of slower robust methods except when they are really needed,
* thus providing better average performance.
* <p>
* Uses an approach due to Jonathan Shewchuk, which is in the public domain.
*
* @param pax A coordinate
* @param pay A coordinate
* @param pbx B coordinate
* @param pby B coordinate
* @param pcx C coordinate
* @param pcy C coordinate
* @return the orientation index if it can be computed safely
* @return i > 1 if the orientation index cannot be computed safely
*/
static int orientationIndexFilterDouble(
double pax, double pay, double pbx, double pby, double pcx, double pcy) {
double detsum;

double detleft = (pax - pcx) * (pby - pcy);
double detright = (pay - pcy) * (pbx - pcx);
double det = detleft - detright;

if (detleft > 0.0) {
if (detright <= 0.0) {
return signum(det);
} else {
detsum = detleft + detright;
}
} else if (detleft < 0.0) {
if (detright >= 0.0) {
return signum(det);
} else {
detsum = -detleft - detright;
}
} else {
return signum(det);
}

double errbound = DP_SAFE_EPSILON * detsum;
if ((det >= errbound) || (-det >= errbound)) {
return signum(det);
}

return 2;
}

static int signum(double x) {
if (x > 0) return 1;
if (x < 0) return -1;
Expand Down Expand Up @@ -221,22 +311,22 @@ class Orientation {
* dependent, when computing the orientation of a point very close to a
* line. This is possibly due to the arithmetic in the translation to the
* origin.
*
*
* For instance, the following situation produces identical results in spite
* of the inverse orientation of the line segment:
*
*
* Coordinate p0 = new Coordinate(219.3649559090992, 140.84159161824724);
* Coordinate p1 = new Coordinate(168.9018919682399, -5.713787599646864);
*
*
* Coordinate p = new Coordinate(186.80814046338352, 46.28973405831556); int
* orient = orientationIndex(p0, p1, p); int orientInv =
* orientationIndex(p1, p0, p);
*
*
* A way to force consistent results is to normalize the orientation of the
* vector using the following code. However, this may make the results of
* orientationIndex inconsistent through the triangle of points, so it's not
* clear this is an appropriate patch.
*
*
*/
return CGAlgorithmsDD.orientationIndex(p1, p2, q);

Expand Down Expand Up @@ -313,7 +403,7 @@ class Orientation {
* If disc is exactly 0, lines are collinear. There are two possible cases:
* (1) the lines lie along the x axis in opposite directions (2) the lines
* lie on top of one another
*
*
* (1) is handled by checking if next is left of prev ==> CCW (2) will never
* happen if the ring is valid, so don't check for it (Might want to assert
* this)
Expand Down Expand Up @@ -412,10 +502,10 @@ class Orientation {
}
return isCCW;
}

static bool isCCWArea(List<Coordinate> ring) {
return Area.ofRingSigned(ring) < 0;
}

}

/// Contains functions to compute intersections between lines.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/com/hydrologis/dart_jts/algorithm/convexthull.dart
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ class ConvexHull {
return null;
}
coordList.closeRing();
return coordList.toCoordinateArray();
return coordList.toCoordinateArray(true);
}

List<Coordinate> computeOctPts(List<Coordinate> inputPts) {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/com/hydrologis/dart_jts/densify/densifier.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Densifier {
}
// this check handles empty sequences
if (pts.length > 0) coordList.addCoord(pts[pts.length - 1], false);
return coordList.toCoordinateArray();
return coordList.toCoordinateArray(true);
}

late Geometry inputGeom;
Expand Down
143 changes: 143 additions & 0 deletions lib/src/com/hydrologis/dart_jts/edgegraph/edge_graph.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
part of dart_jts;

/**
* A graph comprised of {@link HalfEdge}s.
* It supports tracking the vertices in the graph
* via edges incident on them,
* to allow efficient lookup of edges and vertices.
* <p>
* This class may be subclassed to use a
* different subclass of HalfEdge,
* by overriding {@link #createEdge(Coordinate)}.
* If additional logic is required to initialize
* edges then {@link EdgeGraph#addEdge(Coordinate, Coordinate)}
* can be overridden as well.
*
* @author Martin Davis
*
*/
class EdgeGraph {
Map<Coordinate, HalfEdge> vertexMap = {};

EdgeGraph() {}

/**
* Creates a single HalfEdge.
* Override to use a different HalfEdge subclass.
*
* @param orig the origin location
* @return a new HalfEdge with the given origin
*/
HalfEdge createEdge(Coordinate orig) {
return new HalfEdge(orig);
}

/**
* Creates a HalfEge pair, using the HalfEdge type of the graph subclass.
*
* @param p0
* @param p1
* @return
*/
HalfEdge create(Coordinate p0, Coordinate p1) {
HalfEdge e0 = createEdge(p0);
HalfEdge e1 = createEdge(p1);
e0.link(e1);
return e0;
}

/**
* Adds an edge between the coordinates orig and dest
* to this graph.
* Only valid edges can be added (in particular, zero-length segments cannot be added)
*
* @param orig the edge origin location
* @param dest the edge destination location.
* @return the created edge
* @return null if the edge was invalid and not added
*
* @see #isValidEdge(Coordinate, Coordinate)
*/
HalfEdge? addEdge(Coordinate orig, Coordinate dest) {
if (!isValidEdge(orig, dest)) return null;

/**
* Attempt to find the edge already in the graph.
* Return it if found.
* Otherwise, use a found edge with same origin (if any) to construct new edge.
*/
HalfEdge? eAdj = vertexMap[orig];
HalfEdge? eSame = null;
if (eAdj != null) {
eSame = eAdj.find(dest);
}
if (eSame != null) {
return eSame;
}

HalfEdge e = insert(orig, dest, eAdj!);
return e;
}

/**
* Tests if the given coordinates form a valid edge (with non-zero length).
*
* @param orig the start coordinate
* @param dest the end coordinate
* @return true if the edge formed is valid
*/
static bool isValidEdge(Coordinate orig, Coordinate dest) {
int cmp = dest.compareTo(orig);
return cmp != 0;
}

/**
* Inserts an edge not already present into the graph.
*
* @param orig the edge origin location
* @param dest the edge destination location
* @param eAdj an existing edge with same orig (if any)
* @return the created edge
*/
HalfEdge insert(Coordinate orig, Coordinate dest, HalfEdge? eAdj) {
// edge does not exist, so create it and insert in graph
HalfEdge e = create(orig, dest);
if (eAdj != null) {
eAdj.insert(e);
} else {
vertexMap.putIfAbsent(orig, () => e);
}

HalfEdge? eAdjDest = vertexMap[dest];
if (eAdjDest != null) {
eAdjDest.insert(e.symEdge);
} else {
vertexMap.putIfAbsent(dest, () => e.symEdge);
}
return e;
}

/**
* Gets all {@link HalfEdge}s in the graph.
* Both edges of edge pairs are included.
*
* @return a collection of the graph edges
*/
List<HalfEdge> getVertexEdges() {
return vertexMap.values.toList();
}

/**
* Finds an edge in this graph with the given origin
* and destination, if one exists.
*
* @param orig the origin location
* @param dest the destination location.
* @return an edge with the given orig and dest, or null if none exists
*/
HalfEdge? findEdge(Coordinate orig, Coordinate dest) {
HalfEdge? e = vertexMap[orig];
if (e == null) return null;
return e.find(dest);
}
}
Loading

0 comments on commit a5098ab

Please sign in to comment.