LineLabelBaseline.java
/*
* Copyright (c) 2019 Martin Davis
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* and Eclipse Distribution License v. 1.0 which accompanies this distribution.
* The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
* and the Eclipse Distribution License is available at
*
* http://www.eclipse.org/org/documents/edl-v10.php.
*/
package org.locationtech.jtstest.testbuilder.ui.style;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.LineSegment;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jtstest.testbuilder.geom.SegmentClipper;
/**
* Determines a label point for a LineString,
* subject to a constraint envelope.
* The constraint is typically a viewport.
*
* @author mdavis
*
*/
public class LineLabelBaseline {
public static LineSegment getBaseline(LineString line, Envelope constraintEnv) {
LineLabelBaseline labeller = new LineLabelBaseline(line, constraintEnv);
return labeller.getBaseline();
}
private Envelope constraintEnv;
private LineString line;
public LineLabelBaseline(LineString line, Envelope constraintEnv) {
this.line = line;
this.constraintEnv = constraintEnv;
}
public LineSegment getBaseline() {
// iterate over line to find first visible clip segment
for (int i = 0; i < line.getNumPoints() - 1; i++) {
Coordinate seg0 = line.getCoordinateN(i);
Coordinate seg1 = line.getCoordinateN(i + 1);
LineSegment seg = clip(seg0, seg1);
if (seg != null) return seg;
}
return null;
//TODO: find clip segment with midpoint closest to window centre?
//TODO: handle case where start segment of line is almost out of view
}
private LineSegment clip(Coordinate p0, Coordinate p1) {
if (! constraintEnv.intersects(p0, p1))
return null;
Coordinate clip0 = new Coordinate(p0);
Coordinate clip1 = new Coordinate(p1);
SegmentClipper.clip(clip0, clip1, constraintEnv);
if (isOnBoundary(constraintEnv, p0, p1))
return null;
return new LineSegment(clip0, clip1);
}
private boolean isOnBoundary(Envelope env, Coordinate p0, Coordinate p1) {
if (p0.x == p1.x) {
if (p0.x == env.getMinX() || p0.x == env.getMaxX())
return true;
}
if (p0.y == p1.y) {
if (p0.y == env.getMinY() || p0.x == env.getMaxY())
return true;
}
return false;
}
}