/* * Geotoolkit - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009-2010, 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.ext.labeling; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.util.ArrayList; import java.util.List; import org.geotoolkit.display2d.canvas.RenderingContext2D; import org.geotoolkit.display2d.style.labeling.DefaultLabelRenderer; import org.geotoolkit.display2d.style.labeling.LabelDescriptor; import org.geotoolkit.display2d.style.labeling.LabelLayer; import org.geotoolkit.display2d.style.labeling.LinearLabelDescriptor; import org.geotoolkit.display2d.style.labeling.PointLabelDescriptor; import org.geotoolkit.display2d.style.labeling.candidate.Candidate; import org.geotoolkit.display2d.style.labeling.candidate.LabelingUtilities; import org.geotoolkit.display2d.style.labeling.candidate.LinearCandidate; import org.geotoolkit.display2d.style.labeling.candidate.PointCandidate; import org.geotoolkit.display2d.style.labeling.decimate.LinearLabelCandidateRenderer; import org.geotoolkit.display2d.style.labeling.decimate.PointLabelCandidateRenderer; /** * Label renderer that apply a simple decimation on labels to remove all * overlaping labels and try do displace them to achieve good results. * * @author Johann Sorel (Geomatys) * @module */ public class DisplacementLabelRenderer extends DefaultLabelRenderer{ private final List<LabelLayer> layers = new ArrayList<LabelLayer>(); private RenderingContext2D context; private PointLabelCandidateRenderer pointRenderer; private LinearLabelCandidateRenderer LinearRenderer; public DisplacementLabelRenderer() { } /** * {@inheritDoc } */ @Override public void setRenderingContext(final RenderingContext2D context){ super.setRenderingContext(context); LinearRenderer = new LinearLabelCandidateRenderer(context); pointRenderer = new PointLabelCandidateRenderer(context); } /** * {@inheritDoc } */ @Override public RenderingContext2D getRenderingContext() { return context; } /** * {@inheritDoc } */ @Override public void append(final LabelLayer layer) { layers.add(layer); } /** * {@inheritDoc } */ @Override public void portrayLabels(){ final Graphics2D g2 = context.getGraphics(); //enable antialiasing for labels g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); List<Candidate> candidates = new ArrayList<Candidate>(); //generate all the candidates //priority is in the order of the layers provided. int priority = layers.size(); for(final LabelLayer layer : layers){ for(LabelDescriptor label : layer.labels()){ Candidate[] cs = null; if(label instanceof PointLabelDescriptor){ cs = pointRenderer.generateCandidat((PointLabelDescriptor) label); }else if(label instanceof LinearLabelDescriptor){ cs = LinearRenderer.generateCandidat((LinearLabelDescriptor) label); }else{ cs = null; } if(cs != null){ for(Candidate c : cs){ c.setPriority(priority); candidates.add(c); } } } priority--; } //displace or remove the candidates candidates = optimize(candidates); //paint the remaining candidates for(Candidate candidate : candidates){ if(candidate instanceof PointCandidate){ pointRenderer.render(candidate); }else if(candidate instanceof LinearCandidate){ LinearRenderer.render(candidate); } } layers.clear(); } private List<Candidate> optimize(List<Candidate> candidates){ candidates = new ArrayList<Candidate>(SimulatedAnnealing.simulate(candidates, 40, 0.99)); candidates = LabelingUtilities.clipOutofBounds(context,candidates); // candidates = LabelingUtilities.sortByXY(candidates); candidates = LabelingUtilities.sortByCost(candidates); final List<Candidate> cleaned = new ArrayList<Candidate>(); loop: for(int i= candidates.size()-1; i>=0; i--){ Candidate candidate = candidates.get(i); for(Candidate other : cleaned){ if(other == candidate) continue; if(LabelingUtilities.intersects(candidate,other)){ continue loop; } } cleaned.add(candidate); } return cleaned; } }