/* * 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.font.GlyphVector; import java.awt.geom.AffineTransform; import java.awt.geom.Point2D; import java.util.ArrayList; import java.util.List; import com.vividsolutions.jts.geom.Coordinate; /** * Process all the glyphs of label. */ abstract class GlyphVectorProcessor { List<AffineTransform> transforms; LabelPainter painter; public GlyphVectorProcessor(LabelPainter painter) { transforms = new ArrayList<>(); this.painter = painter; } public boolean process(GlyphProcessor processor) { return process(processor, false); } public boolean process(GlyphProcessor processor, boolean stopIfTrue) { int glyphCount = 0; boolean ret = false; for (LineInfo lineInfo : painter.lines) { for (LineInfo.LineComponent lineComponent : lineInfo.getComponents()) { GlyphVector glyphVector = lineComponent.getGlyphVector(); for (int g = 0; g < glyphVector.getNumGlyphs(); g++, glyphCount++) { char c = getChar(lineComponent, glyphVector, g); // warning : do "process || ret", not "ret || process" ret = processor.process(glyphVector, g, transforms.get(glyphCount), c) || ret; if (ret && stopIfTrue) return true; } } } return ret; } /** * Return the character corresponding to this glyphVector index */ public char getChar(LineInfo.LineComponent component, GlyphVector glyphVector, int g) { return component.getText().charAt(glyphVector.getGlyphCharIndex(g)); } /** * Create a Straight GlyphVectorProcessor, pre-compute the affine transforms * for each glyph along a straight line. */ public static class Straight extends GlyphVectorProcessor { public Straight(LabelPainter painter, AffineTransform tx) { super(painter); for (LineInfo lineInfo : painter.lines) { for (LineInfo.LineComponent lineComponent : lineInfo.getComponents()) { AffineTransform componentTx = new AffineTransform(tx); componentTx.translate(lineComponent.getX(), lineInfo.getY()); for (int i = 0; i < lineComponent.getGlyphVector().getNumGlyphs(); i++) { transforms.add(componentTx); } } } } } /** * Create a Curved GlyphVectorProcessor, pre-compute the affine transforms * for each glyph along a curved line. * Does not consider letter orientation (only letter position). * (taken from LabelPainter#paintCurvedLabel). */ public static class Curved extends GlyphVectorProcessor { public Curved(LabelPainter painter, LineStringCursor cursor) { super(painter); // for labels following lines, one can only have one line of text AffineTransform oldTransform = painter.graphics.getTransform(); LineInfo lineInfo = painter.lines.get(0); // first off, check if we are walking the line so that the label is // looking up, if not, reverse the line if (!painter.isLabelUpwards(cursor) && painter.getLabel().isForceLeftToRightEnabled()) { LineStringCursor reverse = cursor.reverse(); reverse.moveTo(cursor.getLineStringLength() - cursor.getCurrentOrdinate()); cursor = reverse; } // find out the true centering position double anchorY = painter.getLinePlacementYAnchor(); // init, move to the starting position double mid = cursor.getCurrentOrdinate(); Coordinate c = new Coordinate(); c = cursor.getCurrentPosition(c); double startOrdinate = mid - painter.getStraightLabelWidth() / 2; if (startOrdinate < 0) startOrdinate = 0; cursor.moveTo(startOrdinate); final double lineHeight = painter.getLineHeight(); for (LineInfo.LineComponent lineComponent : lineInfo.getComponents()) { GlyphVector gv = lineComponent.getGlyphVector(); try { final int numGlyphs = gv.getNumGlyphs(); float nextAdvance = gv.getGlyphMetrics(0).getAdvance() * 0.5f; double start = cursor.getCurrentOrdinate(); for (int i = 0; i < numGlyphs; i++) { Point2D p = gv.getGlyphPosition(i); float advance = nextAdvance; nextAdvance = i < numGlyphs - 1 ? gv.getGlyphMetrics(i + 1).getAdvance() * 0.5f : 0; c = cursor.getCurrentPosition(c); AffineTransform t = new AffineTransform(); t.setToTranslation(c.x, c.y); t.rotate(cursor.getCurrentAngle()); t.translate(-p.getX() - advance, -p.getY() + lineHeight * anchorY); transforms.add(t); cursor.moveTo(cursor.getCurrentOrdinate() + advance + nextAdvance); } // take into account eventual spaces at the end of the glyph cursor.moveTo(start + gv.getGlyphPosition(numGlyphs).getX()); } finally { painter.graphics.setTransform(oldTransform); } } } } }