Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improves the rendering of labels in polygons #778

Merged
merged 2 commits into from
Nov 9, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,26 @@ Occam Labs UG (haftungsbeschränkt)
import static org.deegree.commons.utils.math.MathUtils.isZero;
import static org.deegree.rendering.r2d.OrientationFixer.fixOrientation;

import org.deegree.commons.tom.TypedObjectNode;
import org.deegree.geometry.Envelope;
import org.deegree.geometry.Geometries;
import org.deegree.geometry.Geometry;
import org.deegree.geometry.GeometryFactory;
import org.deegree.geometry.multi.MultiPoint;
import org.deegree.geometry.multi.MultiPolygon;
import org.deegree.geometry.primitive.Point;
import org.deegree.geometry.primitive.Polygon;
import org.deegree.geometry.standard.AbstractDefaultGeometry;
import org.deegree.geometry.standard.DefaultEnvelope;
import org.deegree.geometry.standard.primitive.DefaultPoint;
import org.deegree.geometry.standard.primitive.DefaultSurface;
import org.deegree.style.styling.LineStyling;
import org.deegree.style.styling.PolygonStyling;
import org.deegree.style.styling.components.Stroke;

import java.util.ArrayList;
import java.util.List;

/**
* Responsible for clipping geometries to the area of the viewport.
*
Expand All @@ -66,9 +74,12 @@ Occam Labs UG (haftungsbeschränkt)
*/
class GeometryClipper {

private final Envelope viewPort;

private final Polygon clippingArea;

GeometryClipper( final Envelope viewPort, final int width ) {
this.viewPort = viewPort;
this.clippingArea = calculateClippingArea( viewPort, width );
}

Expand All @@ -92,6 +103,37 @@ private Polygon calculateClippingArea( final Envelope bbox, final int width ) {
* @return the clipped geometry or the original geometry if the geometry lays completely in the drawing area.
*/
Geometry clipGeometry( final Geometry geom ) {
return clipGeometry( geom, clippingArea );
}

/**
* Calculates the points inside the geometry and inside the view port. First the passed geometry is clipped
* by the view port. A multipolygon may result. For each of the polygon in this multipolygon one interior point
* is created
*
* @param geom to create labels for, must not be <code>null</code> and in the same CRS as the viewPort
* @return a MultiPoint with all calculated labels
*/
MultiPoint calculateInteriorPoints( final Geometry geom ) {
if ( geom == null )
return null;
Geometry clippedGeometry = clipGeometry( geom, viewPort );
List<Point> points = new ArrayList<Point>();
if ( clippedGeometry != null && clippedGeometry instanceof DefaultSurface ) {
points.add( ( (DefaultSurface) clippedGeometry ).getInteriorPoint() );
}
if ( clippedGeometry != null && clippedGeometry instanceof MultiPolygon ) {
for ( Polygon p : ( (MultiPolygon) clippedGeometry ) ) {
if ( p instanceof DefaultSurface ) {
points.add( ( (DefaultSurface) p ).getInteriorPoint() );
}
}
}
return new GeometryFactory().createMultiPoint( null, geom.getCoordinateSystem(), points );
}


Geometry clipGeometry( final Geometry geom, Geometry clippingArea ) {
if ( clippingArea != null && !clippingArea.contains( geom ) ) {
try {
Geometry clippedGeometry = clippingArea.getIntersection( geom );
Expand All @@ -106,7 +148,7 @@ Geometry clipGeometry( final Geometry geom ) {
if ( isInvertedOrientation( jtsOrig ) ) {
return clippedGeometry;
}

return fixOrientation( clippedGeometry, clippedGeometry.getCoordinateSystem() );
} catch ( UnsupportedOperationException e ) {
// use original geometry if intersection not supported by JTS
Expand All @@ -115,7 +157,7 @@ Geometry clipGeometry( final Geometry geom ) {
}
return geom;
}

/**
* Check if the passed Geometry is a Polygon (or the first Geometry of a Collection) and the exterior Ring has CW orientation
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,33 +65,29 @@ Occam Labs UG (haftungsbeschränkt)
import org.deegree.geometry.multi.MultiGeometry;
import org.deegree.geometry.multi.MultiLineString;
import org.deegree.geometry.multi.MultiPoint;
import org.deegree.geometry.primitive.Curve;
import org.deegree.geometry.primitive.GeometricPrimitive;
import org.deegree.geometry.primitive.Point;
import org.deegree.geometry.primitive.Surface;
import org.deegree.geometry.primitive.*;
import org.deegree.rendering.r2d.strokes.OffsetStroke;
import org.deegree.rendering.r2d.strokes.TextStroke;
import org.deegree.style.styling.TextStyling;
import org.slf4j.Logger;

/**
* Responsible for creating and rendering of labels. Based on Java2DTextRenderer
*
*
* @author Florian Bingel
* @author last edited by: $Author: stranger $
*
* @version $Revision: $, $Date: $
*/
public class Java2DLabelRenderer implements LabelRenderer {

static final Logger LOG = getLogger( Java2DLabelRenderer.class );

private Java2DRenderer renderer;

private RendererContext context;

private Java2DTextRenderer textRenderer;

private ArrayList<Label> labelList;

public Java2DLabelRenderer( Java2DRenderer renderer, Java2DTextRenderer textRenderer ) {
Expand All @@ -100,7 +96,7 @@ public Java2DLabelRenderer( Java2DRenderer renderer, Java2DTextRenderer textRend
this.textRenderer = textRenderer;
labelList = new ArrayList<Label>();
}

@Override
public void createLabel( TextStyling styling, String text, Collection<Geometry> geoms ) {
for ( Geometry g : geoms ) {
Expand All @@ -109,7 +105,7 @@ public void createLabel( TextStyling styling, String text, Collection<Geometry>
}

@Override
public void createLabel( TextStyling styling, String text, Geometry geom ) {
public void createLabel( TextStyling styling, String text, Geometry geom ) {
if ( geom == null ) {
LOG.debug( "Trying to render null geometry." );
}
Expand All @@ -123,12 +119,12 @@ public void createLabel( TextStyling styling, String text, Geometry geom ) {
}

@Override
public List<Label> getLabels(){
public List<Label> getLabels() {
return labelList;
}

private void handleGeometryTypes( TextStyling styling, String text, Font font, Geometry geom ) {
if( geom == null ) {
if ( geom == null ) {
LOG.warn( "null geometry cannot be handled." );
return;
}
Expand All @@ -138,10 +134,11 @@ private void handleGeometryTypes( TextStyling styling, String text, Font font, G
textRenderer.render( styling, font, text, (Surface) geom );
} else if ( geom instanceof Curve && styling.linePlacement != null ) {
textRenderer.render( styling, font, text, (Curve) geom );
} else if ( geom instanceof Polygon && styling.auto ) {
handlePolygonWithAutoPlacement( styling, font, text, (Polygon) geom );
} else if ( geom instanceof GeometricPrimitive ) {
labelList.add( createLabel( styling, font, text, geom.getCentroid() ) );
}
else if ( geom instanceof MultiPoint ) {
} else if ( geom instanceof MultiPoint ) {
handleMultiGeometry( styling, text, font, (MultiPoint) geom );
} else if ( geom instanceof MultiCurve<?> && styling.linePlacement != null ) {
handleMultiGeometry( styling, text, font, (MultiCurve<?>) geom );
Expand All @@ -156,16 +153,16 @@ else if ( geom instanceof MultiPoint ) {
}

private <T extends Geometry> ArrayList<Label> handleMultiGeometry( TextStyling styling, String text, Font font,
MultiGeometry<T> geom ) {
MultiGeometry<T> geom ) {
ArrayList<Label> list = new ArrayList<Label>();
for ( T g : geom ) {
handleGeometryTypes( styling, text, font, g );
}
return list;
}

@Override
public Label createLabel( TextStyling styling, Font font, String text, Point p ){
public Label createLabel( TextStyling styling, Font font, String text, Point p ) {

TextLayout layout;
synchronized ( FontRenderContext.class ) {
Expand All @@ -175,54 +172,63 @@ public Label createLabel( TextStyling styling, Font font, String text, Point p )
FontRenderContext frc = renderer.graphics.getFontRenderContext();
layout = new TextLayout( text, font, frc );
}

Point2D.Double origin = (Point2D.Double) renderer.worldToScreen.transform( new Point2D.Double( p.get0(), p.get1() ),null );
Label aLable = new Label(layout,styling,font,text,origin,context);

return aLable;

Point2D.Double origin = (Point2D.Double) renderer.worldToScreen.transform(
new Point2D.Double( p.get0(), p.get1() ), null );
return new Label( layout, styling, font, text, origin, context );
}

@Override
public void render( ) {
for( Label l : labelList){
public void render() {
for ( Label l : labelList ) {
render( l );
}
labelList = null;
}

@Override
public void render( List<Label> pLabels ) {
for( Label l : pLabels){
render( l );
}
for ( Label l : pLabels ) {
render( l );
}
}

@Override
public void render( Label pLabel ) {

renderer.graphics.setFont( pLabel.getFont() );
AffineTransform transform = renderer.graphics.getTransform();
renderer.graphics.rotate( toRadians( pLabel.getStyling().rotation ), pLabel.getOrigin().x, pLabel.getOrigin().y );

renderer.graphics.rotate( toRadians( pLabel.getStyling().rotation ), pLabel.getOrigin().x,
pLabel.getOrigin().y );

if ( pLabel.getStyling().halo != null ) {
context.fillRenderer.applyFill( pLabel.getStyling().halo.fill, pLabel.getStyling().uom );

BasicStroke stroke = new BasicStroke( round( 2 * context.uomCalculator.considerUOM( pLabel.getStyling().halo.radius,
pLabel.getStyling().uom ) ),
CAP_BUTT, JOIN_ROUND );
BasicStroke stroke = new BasicStroke(
round( 2 * context.uomCalculator.considerUOM( pLabel.getStyling().halo.radius,
pLabel.getStyling().uom ) ),
CAP_BUTT, JOIN_ROUND );
renderer.graphics.setStroke( stroke );
renderer.graphics.draw( pLabel.getLayout().getOutline( getTranslateInstance( pLabel.getDrawPosition().x, pLabel.getDrawPosition().y ) ) );
renderer.graphics.draw( pLabel.getLayout().getOutline(
getTranslateInstance( pLabel.getDrawPosition().x, pLabel.getDrawPosition().y ) ) );
}

//LOG.debug("LabelRender w:" + pLabel.getLayout().getBounds().getWidth() + " h: "+pLabel.getLayout().getBounds().getHeight()+" x: "+pLabel.getDrawPosition().x + " y: "+pLabel.getDrawPosition().y);
renderer.graphics.setStroke( new BasicStroke() );

context.fillRenderer.applyFill( pLabel.getStyling().fill, pLabel.getStyling().uom );
pLabel.getLayout().draw( renderer.graphics, (float) pLabel.getDrawPosition().x, (float) pLabel.getDrawPosition().y );
pLabel.getLayout().draw( renderer.graphics, (float) pLabel.getDrawPosition().x,
(float) pLabel.getDrawPosition().y );

renderer.graphics.setTransform( transform );
}


private void handlePolygonWithAutoPlacement( TextStyling styling, Font font, String text, Polygon geom ) {
Geometry transformedGeom = renderer.rendererContext.geomHelper.transform( geom );
MultiPoint points = renderer.rendererContext.clipper.calculateInteriorPoints( transformedGeom );
if ( geom == null )
return;
handleMultiGeometry( styling, text, font, (MultiGeometry) points );
}

}