use of com.revolsys.geometry.model.Point in project com.revolsys.open by revolsys.
the class LineMergeGraph method addEdge.
/**
* Adds an Edge, DirectedEdges, and Nodes for the given LineString representation
* of an edge.
* Empty lines or lines with all coordinates equal are not added.
*
* @param line the linestring to add to the graph
*/
public void addEdge(final LineString line) {
if (line.isEmpty()) {
return;
}
final LineString points = line.removeDuplicatePoints();
final int vertexCount = points.getVertexCount();
if (vertexCount > 1) {
final Point fromPoint = points.getPoint(0);
final Point toPoint = points.getPoint(vertexCount - 1);
final Node startNode = getNode(fromPoint);
final Node endNode = getNode(toPoint);
final DirectedEdge directedEdge0 = new LineMergeDirectedEdge(startNode, endNode, points.getPoint(1).newPoint(), true);
final DirectedEdge directedEdge1 = new LineMergeDirectedEdge(endNode, startNode, points.getPoint(vertexCount - 2).newPoint(), false);
final Edge edge = new LineMergeEdge(line);
edge.setDirectedEdges(directedEdge0, directedEdge1);
add(edge);
}
}
use of com.revolsys.geometry.model.Point in project com.revolsys.open by revolsys.
the class LineSequencer method isSequenced.
/**
* Tests whether a {@link Geometry} is sequenced correctly.
* {@link LineString}s are trivially sequenced.
* {@link Lineal}s are checked for correct sequencing.
* Otherwise, <code>isSequenced</code> is defined
* to be <code>true</code> for geometries that are not lineal.
*
* @param geom the geometry to test
* @return <code>true</code> if the geometry is sequenced or is not lineal
*/
public static boolean isSequenced(final Geometry geom) {
if (!(geom instanceof Lineal) || geom instanceof LineString) {
return true;
}
final Lineal lineal = (Lineal) geom;
// the nodes in all subgraphs which have been completely scanned
final Set prevSubgraphNodes = new TreeSet();
Point lastNode = null;
final List currNodes = new ArrayList();
for (int i = 0; i < lineal.getGeometryCount(); i++) {
final LineString line = (LineString) lineal.getGeometry(i);
final Point startNode = line.getPoint(0);
final Point endNode = line.getPoint(line.getVertexCount() - 1);
/**
* If this linestring is connected to a previous subgraph, geom is not sequenced
*/
if (prevSubgraphNodes.contains(startNode)) {
return false;
}
if (prevSubgraphNodes.contains(endNode)) {
return false;
}
if (lastNode != null) {
if (!startNode.equals(lastNode)) {
// start new connected sequence
prevSubgraphNodes.addAll(currNodes);
currNodes.clear();
}
}
currNodes.add(startNode);
currNodes.add(endNode);
lastNode = endNode;
}
return true;
}
use of com.revolsys.geometry.model.Point in project com.revolsys.open by revolsys.
the class OffsetSegmentGenerator method addInsideTurn.
/**
* Adds the offset points for an inside (concave) turn.
*
* @param orientation
* @param addStartPoint
*/
private void addInsideTurn(final int orientation, final boolean addStartPoint) {
final double x00 = this.offset0.getX(0);
final double y00 = this.offset0.getY(0);
final double x01 = this.offset0.getX(1);
final double y01 = this.offset0.getY(1);
final double x10 = this.offset1.getX(0);
final double y10 = this.offset1.getY(0);
final double x11 = this.offset1.getX(1);
final double y11 = this.offset1.getY(1);
/**
* add intersection point of offset segments (if any)
*/
this.li.computeIntersection(x00, y00, x01, y01, x10, y10, x11, y11);
if (this.li.hasIntersection()) {
final Point intersection = this.li.getIntersection(0);
final double intersectionX = intersection.getX();
final double intersectionY = intersection.getY();
this.segList.addPoint(intersectionX, intersectionY);
} else {
/**
* If no intersection is detected,
* it means the angle is so small and/or the offset so
* large that the offsets segments don't intersect.
* In this case we must
* add a "closing segment" to make sure the buffer curve is continuous,
* fairly smooth (e.g. no sharp reversals in direction)
* and tracks the buffer correctly around the corner. The curve connects
* the endpoints of the segment offsets to points
* which lie toward the centre point of the corner.
* The joining curve will not appear in the final buffer outline, since it
* is completely internal to the buffer polygon.
*
* In complex buffer cases the closing segment may cut across many other
* segments in the generated offset curve. In order to improve the
* performance of the noding, the closing segment should be kept as short as possible.
* (But not too short, since that would defeat its purpose).
* This is the purpose of the closingSegFactor heuristic value.
*/
/**
* The intersection test above is vulnerable to robustness errors; i.e. it
* may be that the offsets should intersect very close to their endpoints,
* but aren't reported as such due to rounding. To handle this situation
* appropriately, we use the following test: If the offset points are very
* close, don't add closing segments but simply use one of the offset
* points
*/
this.hasNarrowConcaveAngle = true;
if (MathUtil.distance(x01, y01, x10, y10) < this.distance * INSIDE_TURN_VERTEX_SNAP_DISTANCE_FACTOR) {
this.segList.addPoint(x01, y01);
} else {
// add endpoint of this segment offset
this.segList.addPoint(x01, y01);
/**
* Add "closing segment" of required length.
*/
if (this.closingSegLengthFactor > 0) {
final double midX0 = (this.closingSegLengthFactor * x01 + this.s1X) / (this.closingSegLengthFactor + 1);
final double midY0 = (this.closingSegLengthFactor * y01 + this.s1Y) / (this.closingSegLengthFactor + 1);
this.segList.addPoint(midX0, midY0);
final double midX1 = (this.closingSegLengthFactor * x10 + this.s1X) / (this.closingSegLengthFactor + 1);
final double midY1 = (this.closingSegLengthFactor * y10 + this.s1Y) / (this.closingSegLengthFactor + 1);
this.segList.addPoint(midX1, midY1);
} else {
/**
* This branch is not expected to be used except for testing purposes.
* It is equivalent to the JTS 1.9 logic for closing segments
* (which results in very poor performance for large buffer distances)
*/
this.segList.addPoint(this.s1X, this.s1Y);
}
// */
// add start point of next segment offset
this.segList.addPoint(x10, y10);
}
}
}
use of com.revolsys.geometry.model.Point in project com.revolsys.open by revolsys.
the class OffsetSegmentGenerator method addLimitedMitreJoin.
/**
* Adds a limited mitre join connecting the two reflex offset segments.
* A limited mitre is a mitre which is beveled at the distance
* determined by the mitre ratio limit.
*
* @param offset0 the first offset segment
* @param offset1 the second offset segment
* @param distance the offset distance
* @param mitreLimit the mitre limit ratio
*/
private void addLimitedMitreJoin(final LineSegment offset0, final LineSegment offset1, final double distance, final double mitreLimit) {
final double basePtX = this.s1X;
final double basePtY = this.s1Y;
final double ang0 = Angle.angle2d(basePtX, basePtY, this.s0X, this.s0Y);
final double ang2 = Angle.angle2d(basePtX, basePtY, this.s2X, this.s2Y);
// oriented angle between segments
final double angDiff = Angle.angleBetweenOriented(ang0, ang2);
// half of the interior angle
final double angDiffHalf = angDiff / 2;
// angle for bisector of the interior angle between the segments
final double midAng = Angle.normalize(ang0 + angDiffHalf);
// rotating this by PI gives the bisector of the reflex angle
final double mitreMidAng = Angle.normalize(midAng + Math.PI);
// the miterLimit determines the distance to the mitre bevel
final double mitreDist = mitreLimit * distance;
// the bevel delta is the difference between the buffer distance
// and half of the length of the bevel segment
final double bevelDelta = mitreDist * Math.abs(Math.sin(angDiffHalf));
final double bevelHalfLen = distance - bevelDelta;
// compute the midpoint of the bevel segment
final double bevelMidX = basePtX + mitreDist * Math.cos(mitreMidAng);
final double bevelMidY = basePtY + mitreDist * Math.sin(mitreMidAng);
// compute the mitre midline segment from the corner point to the bevel
// segment midpoint
final LineSegment mitreMidLine = new LineSegmentDouble(2, basePtX, basePtY, bevelMidX, bevelMidY);
// finally the bevel segment endpoints are computed as offsets from
// the mitre midline
final Point bevelEndLeft = mitreMidLine.pointAlongOffset(1.0, bevelHalfLen);
final Point bevelEndRight = mitreMidLine.pointAlongOffset(1.0, -bevelHalfLen);
if (this.side == Position.LEFT) {
this.segList.addPoint(bevelEndLeft);
this.segList.addPoint(bevelEndRight);
} else {
this.segList.addPoint(bevelEndRight);
this.segList.addPoint(bevelEndLeft);
}
}
use of com.revolsys.geometry.model.Point in project com.revolsys.open by revolsys.
the class OffsetSegmentGenerator method addMitreJoin.
/**
* Adds a mitre join connecting the two reflex offset segments.
* The mitre will be beveled if it exceeds the mitre ratio limit.
*
* @param offset0 the first offset segment
* @param offset1 the second offset segment
* @param distance the offset distance
*/
private void addMitreJoin(final double x, final double y, final LineSegment offset0, final LineSegment offset1, final double distance) {
boolean isMitreWithinLimit = true;
double intPtX = 0;
double intPtY = 0;
/**
* This computation is unstable if the offset segments are nearly collinear.
* Howver, this situation should have been eliminated earlier by the check for
* whether the offset segment endpoints are almost coincident
*/
try {
final double line1x1 = offset0.getX(0);
final double line1y1 = offset0.getY(0);
final double line1x2 = offset0.getX(1);
final double line1y2 = offset0.getY(1);
final double line2x1 = offset1.getX(0);
final double line2y1 = offset1.getY(0);
final double line2x2 = offset1.getX(1);
final double line2y2 = offset1.getY(1);
final Point intersection = HCoordinate.intersection(line1x1, line1y1, line1x2, line1y2, line2x1, line2y1, line2x2, line2y2);
intPtX = intersection.getX();
intPtY = intersection.getY();
final double mitreRatio;
if (distance <= 0.0) {
mitreRatio = 1;
} else {
mitreRatio = MathUtil.distance(intPtX, intPtY, x, y) / Math.abs(distance);
}
if (mitreRatio > this.bufParams.getMitreLimit()) {
isMitreWithinLimit = false;
}
} catch (final NotRepresentableException ex) {
isMitreWithinLimit = false;
}
if (isMitreWithinLimit) {
this.segList.addPoint(intPtX, intPtY);
} else {
addLimitedMitreJoin(offset0, offset1, distance, this.bufParams.getMitreLimit());
}
}
Aggregations