/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2008 - 2009, Geomatys
*
* 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.geotoolkit.display2d.service;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import org.geotoolkit.display2d.GO2Utilities;
import org.geotoolkit.display2d.style.CachedSymbolizer;
import org.geotoolkit.display2d.style.renderer.SymbolizerRendererService;
import org.geotoolkit.map.MapLayer;
import static org.apache.sis.util.ArgumentChecks.*;
import org.opengis.style.FeatureTypeStyle;
import org.opengis.style.Fill;
import org.opengis.style.Rule;
import org.opengis.style.Stroke;
import org.opengis.style.Style;
import org.opengis.style.Symbolizer;
import org.apache.sis.measure.Units;
/**
* Factory to create small glyph used in map or application legends.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public final class DefaultGlyphService {
private static final int DEFAULT_GLYPH_WIDTH = 30;
private static final int DEFAULT_GLYPH_HEIGHT = 24;
private DefaultGlyphService(){}
public static BufferedImage create(final Style style, final Dimension dim, final MapLayer layer) {
ensureNonNull("dimension", dim);
ensureNonNull("style", style);
if (dim.height <= 0 || dim.width <= 0) {
throw new IllegalArgumentException("Invalid dimension, height and width must be superior to 0");
}
final BufferedImage buffer = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = buffer.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, dim.width, dim.height);
render(style, new Rectangle(dim), (Graphics2D) g2.create(), layer);
g2.drawRect(0, 0, dim.width - 1, dim.height - 1);
g2.dispose();
return buffer;
}
public static BufferedImage create(final FeatureTypeStyle style, final Dimension dim, final MapLayer layer) {
ensureNonNull("dimension", dim);
ensureNonNull("style", style);
if (dim.height <= 0 || dim.width <= 0) {
throw new IllegalArgumentException("Invalid dimension, height and width must be superior to 0");
}
final BufferedImage buffer = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = buffer.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, dim.width, dim.height);
render(style, new Rectangle(dim), (Graphics2D) g2.create(), layer);
g2.drawRect(0, 0, dim.width - 1, dim.height - 1);
g2.dispose();
return buffer;
}
public static BufferedImage create(final Rule style, Dimension dim, final MapLayer layer) {
ensureNonNull("style", style);
if (dim != null && (dim.height <= 0 || dim.width <= 0)) {
throw new IllegalArgumentException("Invalid dimension, height and width must be superior to 0");
}
if(dim == null){
//search for the best glyph size
dim = new Dimension(DEFAULT_GLYPH_WIDTH,DEFAULT_GLYPH_HEIGHT);
for(Symbolizer symbol : style.symbolizers()){
final SymbolizerRendererService renderer = GO2Utilities.findRenderer(symbol.getClass());
if(renderer != null){
final CachedSymbolizer cache = GO2Utilities.getCached(symbol,null);
final Rectangle2D preferred = renderer.glyphPreferredSize(cache,layer);
if(preferred!= null){
if(preferred.getWidth() > dim.getWidth()) dim.width = (int) preferred.getWidth();
if(preferred.getHeight() > dim.getHeight()) dim.height = (int) preferred.getHeight();
}
}
}
}
final BufferedImage buffer = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = buffer.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, dim.width, dim.height);
render(style, new Rectangle(dim), (Graphics2D) g2.create(), layer);
g2.drawRect(0, 0, dim.width - 1, dim.height - 1);
g2.dispose();
return buffer;
}
public static BufferedImage create(final Symbolizer style, Dimension dim, final MapLayer layer) {
ensureNonNull("style", style);
if (dim != null && (dim.height <= 0 || dim.width <= 0)) {
throw new IllegalArgumentException("Invalid dimension, height and width must be superior to 0");
}
if(dim == null){
//search for the best glyph size
dim = glyphPreferredSize(style, dim, layer);
}
final BufferedImage buffer = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = buffer.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, dim.width, dim.height);
render(style, new Rectangle(dim), (Graphics2D) g2.create(),layer);
g2.drawRect(0, 0, dim.width - 1, dim.height - 1);
g2.dispose();
return buffer;
}
public static BufferedImage create(final Fill fill, Dimension dim, final MapLayer layer) {
ensureNonNull("fill", fill);
if (dim != null && (dim.height <= 0 || dim.width <= 0)) {
throw new IllegalArgumentException("Invalid dimension, height and width must be superior to 0");
}
if(dim == null){
//search for the best glyph size
dim = glyphPreferredSize(fill, dim, layer);
}
final BufferedImage buffer = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = buffer.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, dim.width, dim.height);
render(fill, new Rectangle(dim), (Graphics2D) g2.create(),layer);
g2.drawRect(0, 0, dim.width - 1, dim.height - 1);
g2.dispose();
return buffer;
}
public static BufferedImage create(final Stroke stroke, Dimension dim, final MapLayer layer) {
ensureNonNull("stroke", stroke);
if (dim != null && (dim.height <= 0 || dim.width <= 0)) {
throw new IllegalArgumentException("Invalid dimension, height and width must be superior to 0");
}
if(dim == null){
//search for the best glyph size
dim = glyphPreferredSize(stroke, dim, layer);
}
final BufferedImage buffer = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
final Graphics2D g2 = buffer.createGraphics();
g2.setColor(Color.WHITE);
g2.fillRect(0, 0, dim.width, dim.height);
render(stroke, new Rectangle(dim), (Graphics2D) g2.create(),layer);
g2.drawRect(0, 0, dim.width - 1, dim.height - 1);
g2.dispose();
return buffer;
}
public static void render(final Style style, final Rectangle2D rectangle, final Graphics2D target, final MapLayer layer) {
for(final FeatureTypeStyle fts : style.featureTypeStyles()){
render(fts,rectangle,target,layer);
}
}
public static void render(final FeatureTypeStyle fts, final Rectangle2D rectangle, final Graphics2D target, final MapLayer layer) {
for(final Rule rule : fts.rules()){
render(rule,rectangle,target,layer);
}
}
public static void render(final Rule rule, final Rectangle2D rectangle, final Graphics2D target, final MapLayer layer) {
for(final Symbolizer symbol : rule.symbolizers()){
render(symbol,rectangle,target,layer);
}
}
public static void render(final Symbolizer symbol, final Rectangle2D rectangle, Graphics2D target, final MapLayer layer) {
target = (Graphics2D) target.create();
target.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final SymbolizerRendererService renderer = GO2Utilities.findRenderer(symbol.getClass());
if(renderer != null){
CachedSymbolizer cache = GO2Utilities.getCached(symbol,null);
renderer.glyph(target, rectangle, cache,layer);
}
}
public static void render(final Fill fill, final Rectangle2D rectangle, Graphics2D target, final MapLayer layer) {
target = (Graphics2D) target.create();
target.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
GO2Utilities.renderFill(rectangle, fill, target);
}
public static void render(final Stroke stroke, final Rectangle2D rectangle, Graphics2D target, final MapLayer layer) {
target = (Graphics2D) target.create();
target.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
final Shape line = new Line2D.Double(rectangle.getMinX(), rectangle.getCenterY(), rectangle.getMaxX(), rectangle.getCenterY());
GO2Utilities.renderStroke(line, stroke, Units.POINT, target);
}
public static Dimension glyphPreferredSize(final Style style, Dimension dim, final MapLayer layer){
for(FeatureTypeStyle symbol : style.featureTypeStyles()){
dim = glyphPreferredSize(symbol, dim, layer);
}
if(dim == null) dim = new Dimension(DEFAULT_GLYPH_WIDTH,DEFAULT_GLYPH_HEIGHT);
return dim;
}
public static Dimension glyphPreferredSize(final FeatureTypeStyle style, Dimension dim, final MapLayer layer){
for(Rule symbol : style.rules()){
dim = glyphPreferredSize(symbol, dim, layer);
}
if(dim == null) dim = new Dimension(DEFAULT_GLYPH_WIDTH,DEFAULT_GLYPH_HEIGHT);
return dim;
}
public static Dimension glyphPreferredSize(final Rule style, Dimension dim, final MapLayer layer){
for(Symbolizer symbol : style.symbolizers()){
dim = glyphPreferredSize(symbol, dim, layer);
}
if(dim == null) dim = new Dimension(DEFAULT_GLYPH_WIDTH,DEFAULT_GLYPH_HEIGHT);
return dim;
}
public static Dimension glyphPreferredSize(final Symbolizer style, Dimension dim, final MapLayer layer){
final SymbolizerRendererService renderer = GO2Utilities.findRenderer(style.getClass());
if(renderer != null){
final CachedSymbolizer cache = GO2Utilities.getCached(style,null);
final Rectangle2D preferred = renderer.glyphPreferredSize(cache,layer);
if(preferred!= null){
if(dim == null){
dim = new Dimension((int)preferred.getWidth(), (int)preferred.getHeight());
}else{
if(preferred.getWidth() > dim.getWidth()) dim.width = (int) preferred.getWidth();
if(preferred.getHeight() > dim.getHeight()) dim.height = (int) preferred.getHeight();
}
}
}
//default glyph size
if(dim == null) dim = new Dimension(DEFAULT_GLYPH_WIDTH,DEFAULT_GLYPH_HEIGHT);
return dim;
}
public static Dimension glyphPreferredSize(final Fill fill, Dimension dim, final MapLayer layer){
//default glyph size
if(dim == null){
dim = new Dimension();
}
dim.setSize(DEFAULT_GLYPH_WIDTH, DEFAULT_GLYPH_HEIGHT);
return dim;
}
public static Dimension glyphPreferredSize(final Stroke stroke, Dimension dim, final MapLayer layer){
//default glyph size
if(dim == null){
dim = new Dimension();
}
dim.setSize(DEFAULT_GLYPH_WIDTH, DEFAULT_GLYPH_HEIGHT);
return dim;
}
}