/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2015, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.renderer.label;
import java.awt.Rectangle;
import java.awt.font.GlyphVector;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
/**
* A class to process glyphs.
*/
abstract class GlyphProcessor {
LabelPainter painter;
LabelCacheItem labelItem;
public GlyphProcessor(LabelPainter painter) {
this.painter = painter;
this.labelItem = painter.labelItem;
}
/**
* Process a glyph
* @param glyphVector the GlyphVector containing the glyph to process
* @param g index of the glyph in the GlyphVector
* @param tx affineTransform to use
* @param c character to be processed
* @return a boolean value which exact meaning depends on the concrete implementation
*/
public abstract boolean process(GlyphVector glyphVector, int g, AffineTransform tx, char c);
/**
* Processor used to paint the bounds a glyph
*/
public static class BoundsPainter extends GlyphProcessor {
public BoundsPainter(LabelPainter painter) {
super(painter);
}
public boolean process(GlyphVector glyphVector, int g, AffineTransform tx, char c) {
if (Character.isWhitespace(c))
return false;
painter.graphics.draw(tx
.createTransformedShape(glyphVector.getGlyphOutline(g))
.getBounds2D());
return true;
}
}
/**
* Processor used to detect if a glyph has conflict with an other element
* of the index.
*/
public static class ConflictDetector extends GlyphProcessor {
Rectangle displayArea;
LabelIndex paintedBounds;
LabelIndex groupLabels;
int extraSpace;
double minDistance;
public ConflictDetector(LabelPainter painter, Rectangle displayArea,
LabelIndex paintedBounds, LabelIndex groupLabels) {
super(painter);
this.displayArea = displayArea;
this.paintedBounds = paintedBounds;
this.groupLabels = groupLabels;
int space = labelItem.getSpaceAround();
int haloRadius = Math.round(labelItem.getTextStyle().getHaloFill() != null ? labelItem
.getTextStyle().getHaloRadius() : 0);
extraSpace = space + haloRadius;
minDistance = labelItem.getMinGroupDistance();
}
public boolean process(GlyphVector glyphVector, int g, AffineTransform tx, char c) {
Rectangle2D labelEnvelope = tx
.createTransformedShape(glyphVector.getGlyphLogicalBounds(g)).getBounds2D();
// try to paint the label, the condition under which this happens are complex
// white space character does not conflict with other labels
if (Character.isWhitespace(c))
return false;
else if ((displayArea.contains(labelEnvelope) || labelItem.isPartialsEnabled()) &&
!(labelItem.isConflictResolutionEnabled() && paintedBounds.labelsWithinDistance(labelEnvelope, extraSpace)) &&
!groupLabels.labelsWithinDistance(labelEnvelope, minDistance))
return false;
else
return true; // collision = true
}
}
/**
* Processor used to add a glyph in an index.
*/
public static class IndexAdder extends GlyphProcessor {
LabelIndex index;
public IndexAdder(LabelPainter painter, LabelIndex index) {
super(painter);
this.index = index;
}
public boolean process(GlyphVector glyphVector, int g, AffineTransform tx, char c) {
if (Character.isWhitespace(c))
return false;
Rectangle2D labelEnvelope = tx
.createTransformedShape(glyphVector.getGlyphOutline(g))
.getBounds2D();
index.addLabel(labelItem, labelEnvelope);
return true;
}
}
}