Merge "Issue #2804 Moved wireframe shape clipping to JTSCompiler from GLGeometryObject2D" into development

Former-commit-id: 723ff23ee9 [formerly 723ff23ee9 [formerly 4b48313cb3509bebcfdd79e1df3d746a2d12c6af]]
Former-commit-id: f3d107580f
Former-commit-id: dbc420e917
This commit is contained in:
Nate Jensen 2014-02-14 10:50:38 -06:00 committed by Gerrit Code Review
commit 4963b3cc23
4 changed files with 332 additions and 251 deletions

View file

@ -28,7 +28,6 @@ import java.util.List;
import javax.media.opengl.GL;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.exception.VizException;
import com.raytheon.viz.core.gl.objects.GLVertexBufferObject;
@ -42,7 +41,9 @@ import com.raytheon.viz.core.gl.objects.GLVertexBufferObject;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Jun 3, 2011 mschenke Initial creation
* Jun 3, 2011 mschenke Initial creation
* Feb 14, 2014 2804 mschenke Removed ability to clip points outside
* of a defined IExtent
*
* </pre>
*
@ -54,8 +55,6 @@ public class GLGeometryObject2D {
public static class GLGeometryObjectData {
public IExtent worldExtent;
protected int geometryType;
protected int coordType;
@ -97,7 +96,6 @@ public class GLGeometryObject2D {
this.data = new GLGeometryObjectData(data.geometryType, data.coordType);
this.data.manageIndicies = data.manageIndicies;
this.data.mutable = data.mutable;
this.data.worldExtent = data.worldExtent;
initialize();
}
@ -249,93 +247,12 @@ public class GLGeometryObject2D {
coordBuffer.ensureCapacity(verticesNeeded);
}
double[] output = null;
double[] lastOutput = null;
boolean currentlyInBounds = false;
int curIdx = 0;
// While we haven't gone through entire segment...
while (curIdx < glCoordinates.length) {
// Find next valid point in segment
currentlyInBounds = false;
output = lastOutput = null;
while (!currentlyInBounds && curIdx < glCoordinates.length) {
lastOutput = output;
output = glCoordinates[curIdx];
if (data.worldExtent != null) {
if (output == null) {
++curIdx;
continue;
}
currentlyInBounds = data.worldExtent.contains(output);
} else {
currentlyInBounds = true;
}
if (!currentlyInBounds) {
++curIdx;
}
}
// We found a starting point...
if (currentlyInBounds) {
// Mark current index
int idx = points;
if (lastOutput != null) {
addToBuffer(coordBuffer, lastOutput);
points++;
addToBuffer(coordBuffer, output);
points++;
} else {
addToBuffer(coordBuffer, output);
points++;
}
++curIdx;
boolean done = false;
// Keep going until we run out of screenCoordinates or we find
// one O.B.
while (!done && curIdx < glCoordinates.length) {
lastOutput = output;
output = glCoordinates[curIdx];
if (data.worldExtent != null) {
if (output == null) {
++curIdx;
continue;
}
currentlyInBounds = data.worldExtent.contains(output);
} else {
currentlyInBounds = true;
}
if (currentlyInBounds) {
addToBuffer(coordBuffer, output);
points++;
} else {
done = true;
}
++curIdx;
}
if (done) {
// Had to stop early
addToBuffer(coordBuffer, output);
points++;
}
if (points != idx
&& data.manageIndicies
&& (data.geometryType != GL.GL_LINES || indicies
.isEmpty())) {
indicies.add(idx);
}
}
int idx = points;
for (double[] coordinate : glCoordinates) {
addToBuffer(coordBuffer, coordinate);
points += 1;
}
indicies.add(idx);
}
public void allocate(int points) {

View file

@ -40,7 +40,6 @@ import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.IGraphicsTarget.HorizontalAlignment;
import com.raytheon.uf.viz.core.IGraphicsTarget.LineStyle;
import com.raytheon.uf.viz.core.IGraphicsTarget.VerticalAlignment;
import com.raytheon.uf.viz.core.PixelExtent;
import com.raytheon.uf.viz.core.drawables.IFont;
import com.raytheon.uf.viz.core.drawables.IWireframeShape;
import com.raytheon.uf.viz.core.exception.VizException;
@ -60,7 +59,8 @@ import com.vividsolutions.jts.geom.Coordinate;
*
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* May 27, 2011 mschenke Initial creation
* May 27, 2011 mschenke Initial creation
* Feb 14, 2014 2804 mschenke Removed setting of IExtent for clipping
*
* </pre>
*
@ -87,7 +87,6 @@ public class GLWireframeShape2D implements IWireframeShape {
geomData = new GLGeometryObjectData(GL.GL_LINE_STRIP,
GL.GL_VERTEX_ARRAY);
geomData.mutable = mutable;
geomData.worldExtent = new PixelExtent(gridGeometry.getGridRange());
try {
worldToTargetGrid = TransformFactory.worldToGrid(gridGeometry,

View file

@ -20,9 +20,14 @@
package com.raytheon.viz.core.rsc.jts;
import org.eclipse.swt.graphics.RGB;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
import com.raytheon.uf.common.geospatial.ReferencedGeometry;
import com.raytheon.uf.common.geospatial.util.WorldWrapCorrector;
import com.raytheon.uf.viz.core.IExtent;
import com.raytheon.uf.viz.core.PixelCoverage;
import com.raytheon.uf.viz.core.PixelExtent;
import com.raytheon.uf.viz.core.drawables.IDescriptor;
import com.raytheon.uf.viz.core.drawables.IShadedShape;
import com.raytheon.uf.viz.core.drawables.IWireframeShape;
@ -31,9 +36,12 @@ import com.raytheon.uf.viz.core.map.IMapDescriptor;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryCollection;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.prep.PreparedGeometry;
import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
/**
* Compile JTS Objects into renderable obs
@ -45,6 +53,7 @@ import com.vividsolutions.jts.geom.Polygon;
* Date Ticket# Engineer Description
* ------------ ---------- ----------- --------------------------
* Oct 24, 2006 chammack Initial Creation.
* Feb 14, 2014 2804 mschenke Rewrote to move clipping from GLWireframeShape2D to here
*
* </pre>
*
@ -59,6 +68,81 @@ public class JTSCompiler {
SQUARE, CROSS
};
public static class JTSGeometryData {
private RGB geometryColor;
private boolean worldWrapCorrect;
private PreparedGeometry clippingArea;
private PointStyle pointStyle;
protected JTSGeometryData() {
}
protected JTSGeometryData(JTSGeometryData data) {
setGeometryColor(data.geometryColor);
setWorldWrapCorrect(data.worldWrapCorrect);
setClippingArea(data.clippingArea);
setPointStyle(data.pointStyle);
}
public void setGeometryColor(RGB geometryColor) {
this.geometryColor = geometryColor;
}
public void setWorldWrapCorrect(boolean worldWrapCorrect) {
this.worldWrapCorrect = worldWrapCorrect;
}
private void setClippingArea(PreparedGeometry clippingArea) {
this.clippingArea = clippingArea;
}
public void setClippingArea(Polygon clippingArea) {
setClippingArea(PreparedGeometryFactory.prepare(clippingArea));
}
public void setClippingExtent(IExtent clippingExtent) {
double[] center = clippingExtent.getCenter();
PixelCoverage pc = new PixelCoverage(new Coordinate(center[0],
center[1]), clippingExtent.getWidth() + 2,
clippingExtent.getHeight() + 2);
GeometryFactory factory = new GeometryFactory();
setClippingArea(factory.createPolygon(
factory.createLinearRing(new Coordinate[] { pc.getLl(),
pc.getLr(), pc.getUr(), pc.getUl(), pc.getLl() }),
null));
}
public void setPointStyle(PointStyle pointStyle) {
this.pointStyle = pointStyle;
}
protected RGB getGeometryColor() {
return geometryColor;
}
protected boolean isWorldWrapCorrect() {
return worldWrapCorrect;
}
protected PreparedGeometry getClippingArea() {
return clippingArea;
}
protected boolean isClipping() {
return clippingArea != null;
}
protected PointStyle getPointStyle() {
return pointStyle;
}
}
// TODO: parameterize this: also needs to be expressed in screen pixels
// rather than arbitrary pixel units
private static final double POINT_SIZE = 2.0;
@ -69,10 +153,10 @@ public class JTSCompiler {
protected IDescriptor descriptor;
protected PointStyle pointStyle;
private WorldWrapCorrector corrector;
private JTSGeometryData defaultData;
/**
* Constructor
*
@ -85,11 +169,26 @@ public class JTSCompiler {
*/
public JTSCompiler(IShadedShape shadedShp, IWireframeShape wireShp,
IDescriptor descriptor) {
this(shadedShp, wireShp, descriptor, PointStyle.SQUARE);
this.theShadedShape = shadedShp;
this.theWireframeShape = wireShp;
this.descriptor = descriptor;
if (descriptor instanceof IMapDescriptor) {
this.corrector = new WorldWrapCorrector(
descriptor.getGridGeometry());
}
JTSGeometryData data = new JTSGeometryData();
data.setGeometryColor(DEFAULT_COLOR);
data.setClippingExtent(new PixelExtent(descriptor.getGridGeometry()
.getGridRange()));
data.setWorldWrapCorrect(false);
data.setPointStyle(PointStyle.SQUARE);
this.defaultData = data;
}
/**
* Constructor
* @deprecated Use constructor without {@link PointStyle} and add
* {@link PointStyle} to {@link JTSGeometryData} for a
* {@link Geometry}
*
* @param shadedShp
* the shaded shape object (can be null)
@ -100,242 +199,298 @@ public class JTSCompiler {
* @param pointStyle
* the pointStyle
*/
@Deprecated
public JTSCompiler(IShadedShape shadedShp, IWireframeShape wireShp,
IDescriptor descriptor, PointStyle pointStyle) {
this.theShadedShape = shadedShp;
this.theWireframeShape = wireShp;
this.descriptor = descriptor;
this.pointStyle = pointStyle;
if (descriptor instanceof IMapDescriptor) {
this.corrector = new WorldWrapCorrector(
descriptor.getGridGeometry());
}
this(shadedShp, wireShp, descriptor);
this.defaultData.setPointStyle(pointStyle);
}
private void handlePolygon(Polygon poly, RGB color) {
LineString g;
LineString g2;
Coordinate[] c;
LineString[] rings = null;
// long tRead1 = System.nanoTime();
int numRings;
g = poly.getExteriorRing();
c = g.getCoordinates();
if (theWireframeShape != null) {
double[][] pts = coordToDouble(c);
theWireframeShape.addLineSegment(pts);
}
numRings = poly.getNumInteriorRing();
if (theShadedShape != null) {
rings = new LineString[numRings + 1];
rings[0] = g;
}
// Handle inner rings
for (int k = 0; k < numRings; k++) {
g2 = poly.getInteriorRingN(k);
c = g2.getCoordinates();
if (theWireframeShape != null) {
double[][] pts = coordToDouble(c);
theWireframeShape.addLineSegment(pts);
}
if (theShadedShape != null) {
rings[k + 1] = g2;
}
}
if (theShadedShape != null) {
theShadedShape.addPolygonPixelSpace(rings, color);
}
/**
* @return A new {@link JTSGeometryData} for use with the compiler
*/
public JTSGeometryData createGeometryData() {
return new JTSGeometryData(defaultData);
}
private double[][] coordToDouble(Coordinate[] c) {
private static double[][] coordToDouble(Coordinate[] c) {
double[][] pts = new double[c.length][3];
for (int i = 0; i < pts.length; i++) {
pts[i][0] = c[i].x;
pts[i][1] = c[i].y;
pts[i][2] = 0;
pts[i][2] = c[i].z;
}
return pts;
}
private void handleLineString(LineString line, RGB color) {
if (theWireframeShape != null) {
Coordinate[] c = line.getCoordinates();
double[][] pts = coordToDouble(c);
theWireframeShape.addLineSegment(pts);
/**
* Clips the {@link Geometry} passed in to the clipping area
*
* @param geometry
* @param clippingArea
* @return A clipped Geometry with no parts outside the clippingArea
*/
private static Geometry complexClip(Geometry geometry,
PreparedGeometry clippingArea) {
if (clippingArea.contains(geometry)) {
// Fully contained, don't clip
return geometry;
} else if (clippingArea.intersects(geometry)) {
if (geometry.isValid() == false) {
// Don't try and clip invalid geometries
return geometry;
}
// Intersects, partial clip
return clippingArea.getGeometry().intersection(geometry);
} else {
// No intersection, return empty
return new GeometryFactory()
.createGeometryCollection(new Geometry[0]);
}
}
private void handlePoint(Point point, RGB color) {
// make a square point out of each "point"
private void handlePolygon(Polygon poly, JTSGeometryData data) {
int numInteriorRings = poly.getNumInteriorRing();
LineString[] rings = new LineString[numInteriorRings + 1];
rings[0] = poly.getExteriorRing();
for (int k = 0; k < numInteriorRings; k++) {
rings[k + 1] = poly.getInteriorRingN(k);
}
Coordinate[] c = point.getCoordinates();
if (theWireframeShape != null) {
for (LineString ls : rings) {
handleLineString(ls, data);
}
}
switch (pointStyle) {
if (theShadedShape != null) {
theShadedShape.addPolygonPixelSpace(rings, data.getGeometryColor());
}
}
private void handleLineString(LineString line, JTSGeometryData data) {
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(coordToDouble(line
.getCoordinates()));
}
}
private void handlePoint(Point point, JTSGeometryData data) {
Coordinate coord = point.getCoordinate();
double[][] ll;
switch (data.getPointStyle()) {
case CROSS:
for (Coordinate coord : c) {
double[][] ll = new double[2][3];
ll[0][0] = coord.x - POINT_SIZE;
ll[0][1] = coord.y;
ll[0][2] = 0;
ll = new double[2][3];
ll[0][0] = coord.x - POINT_SIZE;
ll[0][1] = coord.y;
ll[0][2] = 0;
ll[1][0] = coord.x + POINT_SIZE;
ll[1][1] = coord.y;
ll[1][2] = 0;
ll[1][0] = coord.x + POINT_SIZE;
ll[1][1] = coord.y;
ll[1][2] = 0;
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(ll);
}
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(ll);
}
ll[0][0] = coord.x;
ll[0][1] = coord.y - POINT_SIZE;
ll[0][2] = 0;
ll[0][0] = coord.x;
ll[0][1] = coord.y - POINT_SIZE;
ll[0][2] = 0;
ll[1][0] = coord.x;
ll[1][1] = coord.y + POINT_SIZE;
ll[1][2] = 0;
ll[1][0] = coord.x;
ll[1][1] = coord.y + POINT_SIZE;
ll[1][2] = 0;
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(ll);
}
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(ll);
}
break;
default: // use SQUARE
for (Coordinate coord : c) {
ll = new double[5][3];
// UL
ll[0][0] = coord.x - POINT_SIZE;
ll[0][1] = coord.y - POINT_SIZE;
ll[0][2] = 0;
double[][] ll = new double[5][3];
// UL
ll[0][0] = coord.x - POINT_SIZE;
ll[0][1] = coord.y - POINT_SIZE;
ll[0][2] = 0;
// UR
ll[1][0] = coord.x - POINT_SIZE;
ll[1][1] = coord.y + POINT_SIZE;
ll[1][2] = 0;
// UR
ll[1][0] = coord.x - POINT_SIZE;
ll[1][1] = coord.y + POINT_SIZE;
ll[1][2] = 0;
// LR
ll[2][0] = coord.x + POINT_SIZE;
ll[2][1] = coord.y + POINT_SIZE;
ll[2][2] = 0;
// LR
ll[2][0] = coord.x + POINT_SIZE;
ll[2][1] = coord.y + POINT_SIZE;
ll[2][2] = 0;
// LL
ll[3][0] = coord.x + POINT_SIZE;
ll[3][1] = coord.y - POINT_SIZE;
ll[3][2] = 0;
// LL
ll[3][0] = coord.x + POINT_SIZE;
ll[3][1] = coord.y - POINT_SIZE;
ll[3][2] = 0;
// Closing point
ll[4] = ll[0];
// Closing point
ll[4] = ll[0];
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(ll);
}
if (theWireframeShape != null) {
theWireframeShape.addLineSegment(ll);
}
break;
}
}
private void handleGeometryCollection(GeometryCollection coll, RGB color)
throws VizException {
private void handleGeometryCollection(GeometryCollection coll,
JTSGeometryData data, boolean clipped) throws VizException {
int geoms = coll.getNumGeometries();
for (int i = 0; i < geoms; i++) {
Geometry g = coll.getGeometryN(i);
disposition(g, color);
disposition(g, data, clipped);
}
}
private void disposition(Geometry geom, RGB color) throws VizException {
if (geom instanceof Point) {
handlePoint((Point) geom, color);
} else if (geom instanceof GeometryCollection) {
handleGeometryCollection((GeometryCollection) geom, color);
private void disposition(Geometry geom, JTSGeometryData data,
boolean clipped) throws VizException {
if (geom instanceof GeometryCollection) {
handleGeometryCollection((GeometryCollection) geom, data, clipped);
} else if (clipped == false && data.isClipping()) {
geom = complexClip(geom, data.getClippingArea());
if (geom.isEmpty() == false) {
disposition(geom, data, true);
}
} else if (geom instanceof Point) {
handlePoint((Point) geom, data);
} else if (geom instanceof LineString) {
handleLineString((LineString) geom, color);
handleLineString((LineString) geom, data);
} else if (geom instanceof Polygon) {
handlePolygon((Polygon) geom, color);
// Polygon is the only type doing complex clipping so it needs to
// know if the Polygon has been clipped already or not
handlePolygon((Polygon) geom, data);
} else {
throw new VizException("Unknown geometry type: "
+ geom.getClass().getName());
}
}
/**
* @deprecated Use {@link #handle(ReferencedGeometry, JTSGeometryData)}
* @param referencedGeom
* @param color
* @throws VizException
*/
@Deprecated
public void handle(ReferencedGeometry referencedGeom, RGB color)
throws VizException {
if (color == null) {
color = DEFAULT_COLOR;
}
Geometry geom;
try {
geom = referencedGeom.asPixel(this.descriptor.getGridGeometry());
} catch (Exception e) {
throw new VizException("Unable to transform polygon", e);
}
disposition(geom, color);
JTSGeometryData data = createGeometryData();
data.setGeometryColor(color);
handle(referencedGeom, data);
}
/**
* Handle lat lon based geometries, destructive to the passed in geometry.
*
* @deprecated Use {@link #handle(Geometry, JTSGeometryData)}
* @param geom
* @param wrapCorrect
* @throws VizException
*/
public void handle(Geometry geom) throws VizException {
handle(geom, DEFAULT_COLOR);
}
/**
* Handle lat lon based geometries, destructive to the passed in geometry.
*
* @param geom
* @param wrapCheck
* @throws VizException
*/
@Deprecated
public void handle(Geometry geom, boolean wrapCheck) throws VizException {
handle(geom, DEFAULT_COLOR, wrapCheck);
JTSGeometryData data = createGeometryData();
data.setWorldWrapCorrect(wrapCheck);
handle(geom, data);
}
/**
* Handle lat lon based geometries, destructive to the passed in geometry.
*
* @deprecated Use {@link #handle(Geometry, JTSGeometryData)}
* @param geom
* @param color
* @throws VizException
*/
@Deprecated
public void handle(Geometry geom, RGB color) throws VizException {
handle(geom, color, false);
JTSGeometryData data = createGeometryData();
data.setGeometryColor(color);
handle(geom, data);
}
/**
* Handle lat lon based geometries, destructive to the passed in geometry.
*
* @deprecated Use {@link #handle(Geometry, JTSGeometryData)}
* @param geom
* @param color
* @param wrapCorrect
* @throws VizException
*/
@Deprecated
public void handle(Geometry geom, RGB color, boolean wrapCorrect)
throws VizException {
if (wrapCorrect && corrector != null) {
geom = corrector.correct(geom);
JTSGeometryData data = createGeometryData();
data.setGeometryColor(color);
data.setWorldWrapCorrect(wrapCorrect);
handle(new ReferencedGeometry(geom), data);
}
/**
* Handles a Geometry in lat/lon space
*
* @param geom
* @throws VizException
*/
public void handle(Geometry geom) throws VizException {
handle(geom, defaultData);
}
/**
* Handles a Geometry in lat/lon space using the geometry data
*
* @param geom
* @param data
* @throws VizException
*/
public void handle(Geometry geom, JTSGeometryData data) throws VizException {
handle(new ReferencedGeometry(geom), data);
}
/**
* Handles the referenced geometry
*
* @param geom
* @throws VizException
*/
public void handle(ReferencedGeometry geom) throws VizException {
handle(geom, defaultData);
}
/**
* Handles the referenced geometry using the geometry data
*
* @param geom
* @param data
* @throws VizException
*/
public void handle(ReferencedGeometry geom, JTSGeometryData data)
throws VizException {
if (corrector != null && corrector.needsCorrecting()
&& data.isWorldWrapCorrect()) {
try {
geom = new ReferencedGeometry(
corrector.correct(geom.asLatLon()));
} catch (FactoryException e) {
throw new VizException("Error creating transform to Lat/Lon", e);
} catch (TransformException e) {
throw new VizException(
"Error transforming geometry into Lat/Lon", e);
}
}
handle(new ReferencedGeometry(geom), color);
try {
disposition(geom.asPixel(descriptor.getGridGeometry()), data, false);
} catch (FactoryException e) {
throw new VizException(
"Error creating transform to descriptor pixel space", e);
} catch (TransformException e) {
throw new VizException(
"Error transforming geometry into descriptor pixel space",
e);
}
}
}

View file

@ -52,6 +52,8 @@ import com.vividsolutions.jts.geom.prep.PreparedGeometryFactory;
* May 30, 2013 2028 randerso Changed to return simple geometry or
* multi-geometry if possible
* Dec 11, 2013 2619 bsteffen Fix rare dateline bug in flattenGeometry.
* Feb 14, 2013 2804 mschenke Added function fo checking if correcting
* needs to occur.
*
* </pre>
*
@ -81,6 +83,14 @@ public class WorldWrapCorrector {
checker = new WorldWrapChecker(worldEnvelope);
}
/**
* @return True if the corrector needs to do correcting on the
* {@link GeneralGridGeometry} it was created with
*/
public boolean needsCorrecting() {
return checker.needsChecking();
}
/**
* Corrects the Geometry passed in to not wrap if geometry does wrap.
* Geometry must be in normalized lat/lon space (-180 to 180)