diff --git a/modules/library/main/src/main/java/org/geotools/geometry/jts/LiteShape2.java b/modules/library/main/src/main/java/org/geotools/geometry/jts/LiteShape2.java index 3fa78c0e95b..d31bc7c540a 100644 --- a/modules/library/main/src/main/java/org/geotools/geometry/jts/LiteShape2.java +++ b/modules/library/main/src/main/java/org/geotools/geometry/jts/LiteShape2.java @@ -222,6 +222,12 @@ public void setGeometry(Geometry g) throws TransformException, transformGeometry(geometry); } } + + public void setGeometry2(Geometry g){ + if (g != null) { + this.geometry = g; + } + } /** * Tests if the interior of the Shape entirely contains the diff --git a/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java b/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java index 1bc593c5c5a..5c5d8f9f5fc 100644 --- a/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java +++ b/modules/library/main/src/main/java/org/geotools/styling/visitor/UomRescaleStyleVisitor.java @@ -216,6 +216,9 @@ public void visit(LineSymbolizer line) { Stroke copyStroke = copy.getStroke(); rescaleStroke(copyStroke, mapScale, copy.getUnitOfMeasure()); copy.setUnitOfMeasure(NonSI.PIXEL); + + Expression copyPerpendicularOffset = copy.getPerpendicularOffset(); + rescale(copyPerpendicularOffset, mapScale, copy.getUnitOfMeasure()); } @Override diff --git a/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java b/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java index ab0414c5fbd..37d8cdb98b8 100644 --- a/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java +++ b/modules/library/render/src/main/java/org/geotools/renderer/lite/StyledShapePainter.java @@ -53,8 +53,11 @@ 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.MultiPolygon; import com.vividsolutions.jts.geom.Polygon; +import com.vividsolutions.jts.operation.buffer.BufferParameters; +import com.vividsolutions.jts.operation.buffer.OffsetCurveBuilder; /** * A simple class that knows how to paint a Shape object onto a Graphic given a @@ -113,7 +116,7 @@ public void paint(final Graphics2D graphics, final LiteShape2 shape, * @throws FactoryException * @throws TransformException */ - public void paint(final Graphics2D graphics, final LiteShape2 shape, + public void paint(final Graphics2D graphics, LiteShape2 shape, final Style2D style, final double scale, boolean isLabelObstacle) { if (style == null) { // TODO: what's going on? Should not be reached... @@ -259,6 +262,23 @@ public void paint(final Graphics2D graphics, final LiteShape2 shape, if (style instanceof LineStyle2D) { LineStyle2D ls2d = (LineStyle2D) style; + + double perpendicularOffset = ls2d.getPerpendicularOffset(); + if (Math.abs(perpendicularOffset) != 0){ + GeometryFactory factory = new GeometryFactory(); + LineString lineString = factory.createLineString(shape.getGeometry().getCoordinates()); + BufferParameters bufParams = new BufferParameters(); + bufParams.setQuadrantSegments(0); + bufParams.setJoinStyle(BufferParameters.CAP_FLAT); + OffsetCurveBuilder offsetCurveBuilder = new OffsetCurveBuilder(lineString.getPrecisionModel(), bufParams); + Coordinate[] coordinates = offsetCurveBuilder.getOffsetCurve(lineString.getCoordinates(), perpendicularOffset); + LineString offsetLineString = shape.getGeometry().getFactory().createLineString(coordinates); + try { + shape = new LiteShape2(offsetLineString, null, null, false); + } catch (TransformException e) { + } catch (FactoryException e) { + } + } if (ls2d.getStroke() != null) { // see if a graphic stroke is to be used, the drawing method diff --git a/modules/library/render/src/main/java/org/geotools/renderer/style/LineStyle2D.java b/modules/library/render/src/main/java/org/geotools/renderer/style/LineStyle2D.java index 8bd25fd4b01..ab10ce410ff 100644 --- a/modules/library/render/src/main/java/org/geotools/renderer/style/LineStyle2D.java +++ b/modules/library/render/src/main/java/org/geotools/renderer/style/LineStyle2D.java @@ -37,6 +37,7 @@ public class LineStyle2D extends Style2D { protected Paint contour; protected Stroke stroke; + protected double perpendicularOffset; protected Composite contourComposite; /** Holds value of property graphicStroke. */ @@ -61,6 +62,14 @@ public Stroke getStroke() { public void setStroke(Stroke stroke) { this.stroke = stroke; } + + public double getPerpendicularOffset() { + return perpendicularOffset; + } + + public void setPerpendicularOffset(double perpendicularOffset) { + this.perpendicularOffset = perpendicularOffset; + } /** * Returns the contour color for the {@linkplain org.geotools.renderer.geom.Polyline polyline} diff --git a/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java b/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java index eeae7c68ed1..0326b0bf6be 100644 --- a/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java +++ b/modules/library/render/src/main/java/org/geotools/renderer/style/SLDStyleFactory.java @@ -462,6 +462,7 @@ Style2D createLineStyle(Object feature, LineSymbolizer symbolizer, LineStyle2D style = new LineStyle2D(); setScaleRange(style, scaleRange); style.setStroke(getStroke(symbolizer.getStroke(), feature)); + style.setPerpendicularOffset(evalToDouble(symbolizer.getPerpendicularOffset(), feature, 0)); style.setGraphicStroke(getGraphicStroke(symbolizer.getStroke(), feature, scaleRange)); style.setContour(getStrokePaint(symbolizer.getStroke(), feature)); diff --git a/modules/library/render/src/test/java/org/geotools/renderer/lite/PerpendicularOffsetTest.java b/modules/library/render/src/test/java/org/geotools/renderer/lite/PerpendicularOffsetTest.java new file mode 100644 index 00000000000..7b9ca12dba9 --- /dev/null +++ b/modules/library/render/src/test/java/org/geotools/renderer/lite/PerpendicularOffsetTest.java @@ -0,0 +1,79 @@ +package org.geotools.renderer.lite; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; + +import org.geotools.data.property.PropertyDataStore; +import org.geotools.data.simple.SimpleFeatureSource; +import org.geotools.geometry.jts.ReferencedEnvelope; +import org.geotools.map.FeatureLayer; +import org.geotools.map.Layer; +import org.geotools.map.MapContent; +import org.geotools.referencing.crs.DefaultGeographicCRS; +import org.geotools.styling.Style; +import org.geotools.test.TestData; +import org.junit.Before; +import org.junit.Test; + +public class PerpendicularOffsetTest { + + private static final long TIME = 8000; + + StreamingRenderer renderer; + ReferencedEnvelope bounds; + + @Before + public void initialize() throws Exception { + renderer = new StreamingRenderer(); + bounds = new ReferencedEnvelope(0, 10, 0, 10, DefaultGeographicCRS.WGS84); + + //System.setProperty("org.geotools.test.interactive", "true"); + } + + SimpleFeatureSource getData(String name) throws IOException, URISyntaxException { + File property = new File(TestData.getResource(this, name + ".properties").toURI()); + PropertyDataStore ds = new PropertyDataStore(property.getParentFile()); + SimpleFeatureSource fs = ds.getFeatureSource(name); + return fs; + } + + void setupRenderer(String name, Style style) throws IOException, URISyntaxException { + MapContent mc = new MapContent(); + Layer layer = new FeatureLayer(getData(name), style); + mc.addLayer(layer); + renderer.setMapContent(mc); + } + + @Test + public void testDiagonalPerpendicularOffset() throws Exception { + Style style = RendererBaseTest.loadStyle(this, "linePerpendicularOffset.sld"); + + setupRenderer("diaglines", style); + + RendererBaseTest.showRender("Diagonal lines PerpendicularOffset", renderer, TIME, bounds); + } + + @Test + public void testCurvedPerpendicularOffset() throws Exception { + Style style = RendererBaseTest.loadStyle(this, "linePerpendicularOffset.sld"); + + setupRenderer("curvedline", style); + + RendererBaseTest.showRender("Curved line PerpendicularOffset", renderer, TIME, bounds); + } + + /** + * TODO: This test shows a case where the current PerpendicularOffset implementation does not produce a + * valid result. + */ + @Test + public void testNarrowCurvedPerpendicularOffset() throws Exception { + Style style = RendererBaseTest.loadStyle(this, "linePerpendicularOffsetWide.sld"); + + setupRenderer("narrowcurvedline", style); + + RendererBaseTest.showRender("Narrow curved line wide PerpendicularOffset", renderer, TIME, bounds); + } + +} diff --git a/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/curvedline.properties b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/curvedline.properties new file mode 100644 index 00000000000..e02cdfb811d --- /dev/null +++ b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/curvedline.properties @@ -0,0 +1,2 @@ +_=geom:LineString:4326 +Line.1=LINESTRING(1 5, 4 8, 7 6, 6 3, 3 2) \ No newline at end of file diff --git a/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/linePerpendicularOffset.sld b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/linePerpendicularOffset.sld new file mode 100644 index 00000000000..59de7182c6e --- /dev/null +++ b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/linePerpendicularOffset.sld @@ -0,0 +1,35 @@ + + + + + GrayLines + + + + + + 0x000000 + 1 + + + + + 0xff0000 + 1 + + 3 + + + + 0x0000ff + 1 + + -3 + + + + + + \ No newline at end of file diff --git a/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/linePerpendicularOffsetWide.sld b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/linePerpendicularOffsetWide.sld new file mode 100644 index 00000000000..813ffa11be4 --- /dev/null +++ b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/linePerpendicularOffsetWide.sld @@ -0,0 +1,28 @@ + + + + + GrayLines + + + + + + 0x000000 + 1 + + + + + 0xff0000 + 1 + + 5 + + + + + + \ No newline at end of file diff --git a/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/narrowcurvedline.properties b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/narrowcurvedline.properties new file mode 100644 index 00000000000..451b101ae56 --- /dev/null +++ b/modules/library/render/src/test/resources/org/geotools/renderer/lite/test-data/narrowcurvedline.properties @@ -0,0 +1,2 @@ +_=geom:LineString:4326 +Line.1=LINESTRING(1 5, 4 8, 7 6, 5.5 6.9, 3 2) \ No newline at end of file