/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2008 - 2014, 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.style; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.image.BufferedImage; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.logging.Level; import javax.swing.Icon; import org.geotoolkit.display.PortrayalException; import org.geotoolkit.display.shape.TransformedShape; import org.geotoolkit.display2d.GO2Utilities; import org.geotoolkit.renderer.style.DynamicSymbolFactoryFinder; import org.geotoolkit.renderer.style.MarkFactory; import org.opengis.filter.expression.Expression; import org.opengis.metadata.citation.OnlineResource; import org.opengis.style.ExternalMark; import org.opengis.style.Mark; /** * Cached Mark. * * @author Johann Sorel (Geomatys) * @module */ public class CachedMark extends Cache<Mark>{ private static final MarkFactory[] MARK_FACTORIES; static { final List<MarkFactory> lst = new ArrayList<>(); final Iterator<MarkFactory> ite = DynamicSymbolFactoryFinder.getMarkFactories(); while(ite.hasNext()){ lst.add(ite.next()); } MARK_FACTORIES = lst.toArray(new MarkFactory[0]); } //IDS for cache map private Shape cachedWKN = null; private final CachedStrokeSimple cachedStroke; private final CachedFill cachedFill; private CachedMark(final Mark mark){ super(mark); cachedStroke = (CachedStrokeSimple) CachedStroke.cache(mark.getStroke()); cachedFill = CachedFill.cache(mark.getFill()); } /** * {@inheritDoc } */ @Override protected void evaluate() { if(!isNotEvaluated) return; this.isStatic = true; if(!evaluateMark()){ //composite is completely translucent or paint is not visible //we cache nothing seens nothing can be render cachedWKN = null; requieredAttributs = EMPTY_ATTRIBUTS; isStatic = true; } if(!cachedStroke.isStatic()) isStatic = false; if(!cachedFill.isStatic()) isStatic = false; if(cachedFill.isStaticVisible() == VisibilityState.UNVISIBLE && cachedStroke.isStaticVisible() == VisibilityState.UNVISIBLE && styleElement.getExternalMark() == null ){ //we have a Well Knowned mark but it's invisible //so nothing to cache cachedWKN = null; requieredAttributs = EMPTY_ATTRIBUTS; isStatic = true; isStaticVisible = VisibilityState.UNVISIBLE; } isNotEvaluated = false; } private boolean evaluateMark(){ final Expression expWKN = styleElement.getWellKnownName(); boolean isWKN = false; if(expWKN == null){ isWKN = false; }else if(GO2Utilities.isStatic(expWKN)){ Object markRef = expWKN.evaluate(null); for(int i=0; i<MARK_FACTORIES.length && cachedWKN==null; i++){ try { cachedWKN = MARK_FACTORIES[i].evaluateShape(null, markRef, 0); } catch (PortrayalException ex) { LOGGER.log(Level.WARNING, ex.getLocalizedMessage(),ex); } } //we return false, invalid marker if(cachedWKN == null){ isStaticVisible = VisibilityState.UNVISIBLE; return false; } //this style is visible if(isStaticVisible == VisibilityState.NOT_DEFINED) isStaticVisible = VisibilityState.VISIBLE; isWKN = true; }else{ //this style visibility is dynamic if(isStaticVisible == VisibilityState.NOT_DEFINED) isStaticVisible = VisibilityState.VISIBLE; isStatic = false; GO2Utilities.getRequieredAttributsName(expWKN,requieredAttributs); isWKN = true; } final ExternalMark external = styleElement.getExternalMark(); if(!isWKN && external != null){ //no well knowned mark but an external mark return true; }else if(!isWKN){ // no well knowned mark and no external isStaticVisible = VisibilityState.UNVISIBLE; isStatic = true; return false; } return true; } public boolean isValid(){ evaluate(); return styleElement.getWellKnownName()!= null || styleElement.getExternalMark() != null ; } public Shape getShape(final Object candidate, final RenderingHints hints){ evaluate(); final Expression wkn = styleElement.getWellKnownName(); final ExternalMark external = styleElement.getExternalMark(); Shape candidateShape = cachedWKN; if(candidateShape == null){ String format = null; Object markRef = null; int markIndex = 0; if(wkn!=null){ markRef = wkn.evaluate(candidate); }else if(external!=null){ format = external.getFormat(); markRef = external.getOnlineResource().getLinkage().toString(); markIndex = external.getMarkIndex(); } for(int i=0; i<MARK_FACTORIES.length && candidateShape==null; i++){ try { candidateShape = MARK_FACTORIES[i].evaluateShape(format, markRef, markIndex); } catch (PortrayalException ex) { LOGGER.log(Level.WARNING, ex.getLocalizedMessage(),ex); } } } return candidateShape; } public BufferedImage getImage(final Object candidate, final Float size, final RenderingHints hints){ evaluate(); final Expression wkn = styleElement.getWellKnownName(); final ExternalMark external = styleElement.getExternalMark(); int j2dSize = 16; float margin = 0; int maxWidth = 0; int center = 0; Shape candidateShape = getShape(candidate, hints); if(wkn != null || external != null){ j2dSize = (size != null) ? size.intValue() : 16; if(j2dSize < 0) j2dSize = 0; if(j2dSize > 1000) j2dSize = 1000; margin = cachedStroke.getMargin(candidate,1); maxWidth = (int)(margin*2+0.5f)+ j2dSize ; center = maxWidth/2 ; } if(maxWidth < 1) maxWidth =1; if(candidateShape != null){ BufferedImage buffer = new BufferedImage( maxWidth , maxWidth, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = (Graphics2D) buffer.getGraphics(); if(hints != null) g2.setRenderingHints(hints); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.translate(center,center); TransformedShape trs = new TransformedShape(); trs.setOriginalShape(candidateShape); trs.scale(j2dSize,j2dSize); Shape shp = trs; //trs.createTransformedShape(marker); //test if we need to paint the fill if(cachedFill.isVisible(candidate)){ g2.setPaint(cachedFill.getJ2DPaint(candidate,0, 0, 1,hints)); g2.setComposite(cachedFill.getJ2DComposite(candidate)); g2.fill(shp); } //test if we need to paint the stroke if(cachedStroke.isVisible(candidate)){ g2.setStroke(cachedStroke.getJ2DStroke(candidate,1)); g2.setPaint(cachedStroke.getJ2DPaint(candidate, 0, 0, 1, hints)); g2.setComposite(cachedStroke.getJ2DComposite(candidate)); g2.draw(shp); } g2.dispose(); return buffer; }else if(external != null){ return createImage(external, j2dSize, hints); } return null; } private BufferedImage createImage(final ExternalMark external, final int j2dSize, final RenderingHints hints){ final String format = external.getFormat(); final Icon icon = external.getInlineContent(); final int index = external.getMarkIndex(); final OnlineResource online = external.getOnlineResource(); if(icon != null){ int height = icon.getIconHeight(); int width = icon.getIconWidth(); BufferedImage buffer = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g2 = (Graphics2D) buffer.getGraphics(); if(hints != null) g2.setRenderingHints(hints); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); icon.paintIcon(null, g2, 0,0); g2.dispose(); if(height != j2dSize){ //Specification says size is for the hight and we must preserve width float aspect = (float)(height) / j2dSize ; float maxwidth = width / aspect; BufferedImage buffer2 = new BufferedImage( (int)(maxwidth+0.5f), (int)(j2dSize+0.5f), BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) buffer2.getGraphics(); if(hints != null) g.setRenderingHints(hints); g.drawImage(buffer, 0, 0,buffer2.getWidth(), buffer2.getHeight(), 0, 0, width, height,null); g.dispose(); return buffer2; }else{ return buffer; } }else if(online != null){ //TODO a faire return null; } return null; } /** * {@inheritDoc } */ @Override public boolean isVisible(final Object candidate) { evaluate(); if(isStaticVisible == VisibilityState.VISIBLE){ //visible whatever feature we have return true; }else if(isStaticVisible == VisibilityState.UNVISIBLE){ //unvisible whatever feature we have return false; }else{ //dynamic visibility //a markis allways visible, //expect if while evaluating no valid graphic where found return true; } } public static CachedMark cache(final Mark mark){ return new CachedMark(mark); } }