/**
* OrbisGIS is a java GIS application dedicated to research in GIScience.
* OrbisGIS is developed by the GIS group of the DECIDE team of the
* Lab-STICC CNRS laboratory, see <http://www.lab-sticc.fr/>.
*
* The GIS group of the DECIDE team is located at :
*
* Laboratoire Lab-STICC – CNRS UMR 6285
* Equipe DECIDE
* UNIVERSITÉ DE BRETAGNE-SUD
* Institut Universitaire de Technologie de Vannes
* 8, Rue Montaigne - BP 561 56017 Vannes Cedex
*
* OrbisGIS is distributed under GPL 3 license.
*
* Copyright (C) 2007-2014 CNRS (IRSTV FR CNRS 2488)
* Copyright (C) 2015-2017 CNRS (Lab-STICC UMR CNRS 6285)
*
* This file is part of OrbisGIS.
*
* OrbisGIS is free software: you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, either version 3 of the License, or (at your option) any later
* version.
*
* OrbisGIS 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* OrbisGIS. If not, see <http://www.gnu.org/licenses/>.
*
* For more information, please consult: <http://www.orbisgis.org/>
* or contact directly:
* info_at_ orbisgis.org
*/
package org.orbisgis.legend.thematic.categorize;
import org.orbisgis.coremap.renderer.se.AreaSymbolizer;
import org.orbisgis.coremap.renderer.se.Symbolizer;
import org.orbisgis.coremap.renderer.se.common.Uom;
import org.orbisgis.coremap.renderer.se.fill.Fill;
import org.orbisgis.coremap.renderer.se.fill.SolidFill;
import org.orbisgis.coremap.renderer.se.parameter.color.ColorParameter;
import org.orbisgis.coremap.renderer.se.parameter.real.RealParameter;
import org.orbisgis.coremap.renderer.se.parameter.string.StringParameter;
import org.orbisgis.coremap.renderer.se.stroke.PenStroke;
import org.orbisgis.coremap.renderer.se.stroke.Stroke;
import org.orbisgis.legend.structure.categorize.CategorizedColor;
import org.orbisgis.legend.structure.categorize.CategorizedLegend;
import org.orbisgis.legend.structure.categorize.CategorizedReal;
import org.orbisgis.legend.structure.categorize.CategorizedString;
import org.orbisgis.legend.structure.recode.type.TypeEvent;
import org.orbisgis.legend.structure.recode.type.TypeListener;
import org.orbisgis.legend.thematic.AreaParameters;
import org.orbisgis.legend.thematic.EnablesStroke;
import org.orbisgis.legend.thematic.uom.StrokeUom;
import org.xnap.commons.i18n.I18n;
import org.xnap.commons.i18n.I18nFactory;
import java.awt.*;
import java.util.LinkedList;
import java.util.List;
/**
* This class intends to propose an API that is useful to handle {@link AreaSymbolizer} instances that are made
* of literal or categorized parameters.
* @author Alexis Guéganno
*/
public class CategorizedArea extends AbstractCategorizedLegend<AreaParameters>
implements EnablesStroke {
private CategorizedColor colorFill;
private CategorizedReal opacityFill;
private CategorizedReal opacityStroke = null;
private CategorizedColor colorStroke = null;
private CategorizedString dashStroke = null;
private CategorizedReal widthStroke = null;
private boolean strokeEnabled = false;
private AreaSymbolizer symbolizer;
private static final I18n I18N = I18nFactory.getI18n(CategorizedLine.class);
public static final String NAME = I18N.tr("Interval Classification - Area");
/**
* Builds a new, empty, {@code CategorizedArea}.
*/
public CategorizedArea(){
this(new AreaSymbolizer());
}
/**
* Build a new CategorizedArea from the given AreaSymbolizer. This one must have been built with a SolidFill and a
* PenStroke containing a SolidFill. All the parameters must either be simple Categorize or Literal instances. If not,
* Exception will be thrown.
* @param as The input AreaSymbolizer
* @throws IllegalArgumentException If the input symbolizer cannot be recognized as a CategorizedArea.
*/
public CategorizedArea(AreaSymbolizer as){
symbolizer = as;
Stroke str = as.getStroke();
if(str instanceof PenStroke){
strokeEnabled = true;
PenStroke ps = (PenStroke) str;
dashStroke = new CategorizedString(ps.getDashArray());
widthStroke = new CategorizedReal(ps.getWidth());
if(ps.getFill() instanceof SolidFill){
SolidFill sf = (SolidFill) ps.getFill();
colorStroke = new CategorizedColor(sf.getColor());
opacityStroke = new CategorizedReal(sf.getOpacity());
} else {
throw new IllegalArgumentException("Can't recognize a Categorized symbol in the input symbolizer.");
}
} else if(str != null) {
throw new IllegalArgumentException("Can't recognize a Categorized symbol in the input symbolizer.");
}
Fill f= as.getFill();
if(f instanceof SolidFill){
SolidFill sf = (SolidFill) f;
colorFill = new CategorizedColor(sf.getColor());
opacityFill = new CategorizedReal(sf.getOpacity());
} else {
throw new IllegalArgumentException("Can't recognize a Categorized symbol in the input symbolizer.");
}
feedListeners();
}
private void feedListeners(){
final SolidFill pointFill = (SolidFill) symbolizer.getFill();
TypeListener cfListener = new TypeListener() {
@Override
public void typeChanged(TypeEvent te) {
ColorParameter p = (ColorParameter) te.getSource().getParameter();
pointFill.setColor(p);
}
};
colorFill.addListener(cfListener);
TypeListener ofListener = new TypeListener() {
@Override public void typeChanged(TypeEvent te) {
RealParameter p = (RealParameter) te.getSource().getParameter();
pointFill.setOpacity(p);
}
};
opacityFill.addListener(ofListener);
if(strokeEnabled){
feedStrokeListeners();
}
}
private void feedStrokeListeners(){
final PenStroke pointStroke = (PenStroke) symbolizer.getStroke();
final SolidFill strokeFill = (SolidFill) pointStroke.getFill();
TypeListener psColListener = new TypeListener() {
@Override public void typeChanged(TypeEvent te) {
ColorParameter p = (ColorParameter) te.getSource().getParameter();
strokeFill.setColor(p);
}
};
colorStroke.addListener(psColListener);
TypeListener psOpListener = new TypeListener() {
@Override public void typeChanged(TypeEvent te) {
RealParameter p = (RealParameter) te.getSource().getParameter();
strokeFill.setOpacity(p);
}
};
opacityStroke.addListener(psOpListener);
TypeListener dashListener = new TypeListener() {
@Override public void typeChanged(TypeEvent te) {
StringParameter p = (StringParameter) te.getSource().getParameter();
pointStroke.setDashArray(p);
}
};
dashStroke.addListener(dashListener);
TypeListener widthListener = new TypeListener() {
@Override public void typeChanged(TypeEvent te) {
RealParameter p = (RealParameter) te.getSource().getParameter();
pointStroke.setWidth(p);
}
};
widthStroke.addListener(widthListener);
}
@Override
public List<CategorizedLegend> getCategorizedLegend() {
List<CategorizedLegend> ret = new LinkedList<CategorizedLegend>();
if(strokeEnabled){
ret.add(colorStroke);
ret.add(opacityStroke);
ret.add(widthStroke);
ret.add(dashStroke);
}
ret.add(colorFill);
ret.add(opacityFill);
return ret;
}
@Override
public Symbolizer getSymbolizer() {
return symbolizer;
}
@Override
public String getLegendTypeName() {
return NAME;
}
@Override
public AreaParameters get(Object o) {
if(!(o instanceof Double)){
throw new IllegalArgumentException("Keys are double values in this map");
}
Double d = (Double)o;
double w;
Color sc;
String da;
Double sop;
if(strokeEnabled){
w = widthStroke.getFromLower(d);
sc = colorStroke.getFromLower(d);
da = dashStroke.getFromLower(d);
sop = opacityStroke.getFromLower(d);
} else {
w = .0;
sc = Color.WHITE;
da = "";
sop = .0;
}
return new AreaParameters(sc,sop,w,da,colorFill.getFromLower(d),opacityFill.getFromLower(d));
}
@Override
public AreaParameters put(Double d, AreaParameters ap) {
forceMapping(d);
AreaParameters ret = null;
if(containsKey(d)){
ret = get(d);
}
if(strokeEnabled){
colorStroke.put(d, ap.getLineColor());
opacityStroke.put(d, ap.getLineOpacity());
widthStroke.put(d,ap.getLineWidth());
dashStroke.put(d, ap.getLineDash());
}
colorFill.put(d, ap.getFillColor());
opacityFill.put(d, ap.getFillOpacity());
return ret;
}
private void forceMapping(Double d){
Double upper = getNextThreshold(d);
if(upper < Double.POSITIVE_INFINITY){
if(strokeEnabled){
Color c = colorStroke.getFromLower(upper);
Double aop = opacityStroke.getFromLower(upper);
Double aw = widthStroke.getFromLower(upper);
String ada = dashStroke.getFromLower(upper);
colorStroke.put(upper, c);
opacityStroke.put(upper,aop);
widthStroke.put(upper,aw);
dashStroke.put(upper, ada);
}
Color c = colorFill.getFromLower(upper);
Double aop = opacityFill.getFromLower(upper);
colorFill.put(upper, c);
opacityFill.put(upper,aop);
}
}
@Override
public AreaParameters remove(Object o) {
if(!(o instanceof Double)){
throw new IllegalArgumentException("Keys are double values in this map");
}
Double inp = (Double)o;
forceMapping(inp);
AreaParameters ret;
if(containsKey(inp)){
ret = get(inp);
} else {
return null;
}
if(strokeEnabled){
colorStroke.remove(inp);
opacityStroke.remove(inp);
widthStroke.remove(inp);
dashStroke.remove(inp);
}
colorFill.remove(inp);
opacityFill.remove(inp);
return ret;
}
@Override
public void setFallbackParameters(AreaParameters fallback) {
if(strokeEnabled){
colorStroke.setFallbackValue(fallback.getLineColor());
opacityStroke.setFallbackValue(fallback.getLineOpacity());
dashStroke.setFallbackValue(fallback.getLineDash());
widthStroke.setFallbackValue(fallback.getLineWidth());
}
colorFill.setFallbackValue(fallback.getFillColor());
opacityFill.setFallbackValue(fallback.getFillOpacity());
}
@Override
public AreaParameters getFallbackParameters() {
return new AreaParameters(
strokeEnabled ? colorStroke.getFallbackValue() : Color.WHITE,
strokeEnabled ? opacityStroke.getFallbackValue() : .0,
strokeEnabled ? widthStroke.getFallbackValue() : .0,
strokeEnabled ? dashStroke.getFallbackValue() : "",
colorFill.getFallbackValue(),
opacityFill.getFallbackValue());
}
@Override
public boolean isStrokeEnabled() {
return strokeEnabled;
}
@Override
public void setStrokeEnabled(boolean enable) {
if(strokeEnabled && !enable){
symbolizer.setStroke(null);
} else if (!strokeEnabled && enable){
PenStroke ps = new PenStroke();
String fieldName = getLookupFieldName();
symbolizer.setStroke(ps);
colorStroke = new CategorizedColor(((SolidFill)ps.getFill()).getColor());
opacityStroke = new CategorizedReal(((SolidFill)ps.getFill()).getOpacity());
widthStroke = new CategorizedReal(ps.getWidth());
dashStroke = new CategorizedString(ps.getDashArray());
colorStroke.setLookupFieldName(fieldName);
opacityStroke.setLookupFieldName(fieldName);
widthStroke.setLookupFieldName(fieldName);
dashStroke.setLookupFieldName(fieldName);
feedStrokeListeners();
}
strokeEnabled = enable;
}
@Override
public Uom getStrokeUom() {
return symbolizer.getUom();
}
@Override
public void setStrokeUom(Uom u) {
symbolizer.setUom(u);
}
@Override
public String getLegendTypeId(){
return "org.orbisgis.legend.thematic.categorize.CategorizedArea";
}
}