/**
* 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.coremap.renderer.se.graphic;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.*;
import java.util.Map;
import org.orbisgis.coremap.renderer.se.parameter.ParameterException;
import org.orbisgis.coremap.renderer.se.parameter.real.RealParameter;
import org.orbisgis.coremap.renderer.se.visitors.FeaturesVisitor;
import org.xnap.commons.i18n.I18n;
import org.xnap.commons.i18n.I18nFactory;
/**
* {@code WellKnownName} instances are used to build simple vectorial {@link MarkGraphic}.
* There are six types of {@code WellKnownName} :
* <ul><li>SQUARE</li>
* <li>CIRCLE</li>
* <li>HALFCIRCLE</li>
* <li>TRIANGLE</li>
* <li>STAR</li>
* <li>CROSS</li>
* <li>X</li>
* </ul>
*
* @author Alexis Guéganno, Maxence Laurent
*/
public enum WellKnownName implements MarkGraphicSource {
SQUARE, CIRCLE, HALFCIRCLE, TRIANGLE, STAR, CROSS, X;
/**
* Default size to be used to render graphics based on well-known names.
*/
public static final double DEFAULT_SIZE = 10.0;
private static I18n I18N = I18nFactory.getI18n(WellKnownName.class);
/**
* Get all the {@code String} values that can be used to build a {@code WellKnownName}.
* @return
* An array of lega {@code String} values
*/
public static String[] getValues(){
String[] list = new String[WellKnownName.values().length];
int i = 0;
for (WellKnownName wkn : WellKnownName.values()){
list[i] = wkn.toString();
i++;
}
return list;
}
/**
* Gets an array containing the localized strings associated to the
* string representation of all the units of mesure contained in this
* enum.
* @return
*/
public static String[] getLocalizedStrings(){
WellKnownName[] vals = WellKnownName.values();
String[] ls = new String[vals.length];
for(int i=0; i<vals.length; i++){
ls[i] = vals[i].toLocalizedString();
}
return ls;
}
/**
* Gets the localized representation of this.
* @return
*/
public String toLocalizedString(){
switch (this) {
case SQUARE:
return I18N.tr("SQUARE");
case HALFCIRCLE:
return I18N.tr("HALFCIRCLE");
case TRIANGLE:
return I18N.tr("TRIANGLE");
case STAR:
return I18N.tr("STAR");
case CROSS:
return I18N.tr("CROSS");
case X:
return I18N.tr("X");
default:
return I18N.tr("CIRCLE");
}
}
/**
* Build a new {@code WellKnownName} from a {@code String token}.
* @param tok
* @return
* A {@code WellKnownName} value. Defaults to {@link #CIRCLE} if the name does not match anything.
*/
public static WellKnownName fromString(String tok){
String token = tok == null ? "" : tok;
if (token.equalsIgnoreCase(I18n.marktr("SQUARE"))){
return SQUARE;
} else if (token.equalsIgnoreCase(I18n.marktr("HALFCIRCLE"))){
return HALFCIRCLE;
} else if (token.equalsIgnoreCase(I18n.marktr("TRIANGLE"))){
return TRIANGLE;
} else if (token.equalsIgnoreCase(I18n.marktr("STAR"))){
return STAR;
} else if (token.equalsIgnoreCase(I18n.marktr("CROSS"))){
return CROSS;
} else if (token.equalsIgnoreCase(I18n.marktr("X"))){
return X;
} else{
return CIRCLE;
}
}
@Override
public Shape getShape(ViewBox viewBox, Map<String,Object> map,
Double scale, Double dpi, RealParameter markIndex,
String mimeType) throws ParameterException {
if (map == null && viewBox != null){
FeaturesVisitor fv = new FeaturesVisitor();
viewBox.acceptVisitor(fv);
if(!fv.getResult().isEmpty()){
return null;
}
}
double x=DEFAULT_SIZE, y=DEFAULT_SIZE; // The size of the shape, [final unit] => [px]
if (viewBox != null && viewBox.usable()) {
Point2D box = viewBox.getDimensionInPixel(map, MarkGraphic.DEFAULT_SIZE, MarkGraphic.DEFAULT_SIZE, scale, dpi);
x = box.getX();
y = box.getY();
}
int x2 = (int)(x / 2.0);
int y2 = (int)(y / 2.0);
int minxy6 = (int)Math.min(x/6, y/6);
switch (this) {
case HALFCIRCLE:
if(x2>=0){
return new Arc2D.Double(-x2, -Math.abs(y2), Math.abs(x), Math.abs(y), -90, -180, Arc2D.CHORD);
} else {
return new Arc2D.Double(x2, -Math.abs(y2), Math.abs(x), Math.abs(y), -90, 180, Arc2D.CHORD);
}
case CIRCLE:
return new Ellipse2D.Double(-Math.abs(x2), -Math.abs(y2), Math.abs(x), Math.abs(y));
case TRIANGLE: {
int h3 = (int) (y / 3);
Polygon polygon = new Polygon();
polygon.addPoint((int) x2, h3);
polygon.addPoint((int) -x2, h3);
polygon.addPoint(0, -2 * h3);
polygon.addPoint((int) x2, h3);
return polygon;
}
case STAR: // 5 branches
{
double crx = x2 * (2.0 / 5.0);
double cry = y2 * (2.0 / 5.0);
Polygon star = new Polygon();
final double cos1 = 0.587785252292472915058851867798;
final double cos2 = 0.951056516295153531181938433292;
final double sin1 = 0.809016994374947562285171898111;
final double sin2 = 0.309016994374947617796323129369;
star.addPoint(0, (int) (cry - 0.5));
// alpha = 234
star.addPoint((int) (-cos1 * x2 + 0.5), (int) (sin1 * y2 - 0.5));
// alpha = 198
star.addPoint((int) (-cos2 * crx + 0.5), (int) (sin2 * cry - 0.5));
// alpha = 162
star.addPoint((int) (-cos2 * x2 + 0.5), (int) (-sin2 * y2 - 0.5));
// alpha = 126
star.addPoint((int) (-cos1 * crx + 0.5), (int) (-sin1 * cry - 0.5));
// alpha = 90
star.addPoint(0, (int) (-y2 - 0.5));
// alpha = 54
star.addPoint((int) (cos1 * crx + 0.5), (int) (-sin1 * cry - 0.5));
// alpha = 18
star.addPoint((int) (cos2 * x2 + 0.5), (int) (-sin2 * y2 - 0.5));
// alpha = 342
star.addPoint((int) (cos2 * crx + 0.5), (int) (sin2 * cry - 0.5));
// alpha = 306
star.addPoint((int) (cos1 * x2 + 0.5), (int) (sin1 * y2 - 0.5));
// alpha = 270
star.addPoint(0, (int) (cry - 0.5));
//return star;
//return new Area(star);
//return new Polygon()
return new GeneralPath(star);
}
case CROSS:// TODO IMPLEMENT
Polygon cross = new Polygon();
cross.addPoint(-minxy6, -y2);
cross.addPoint(minxy6, -y2);
cross.addPoint(minxy6, -minxy6);
cross.addPoint(x2, -minxy6);
cross.addPoint(x2, minxy6);
cross.addPoint(minxy6, minxy6);
cross.addPoint(minxy6, y2);
cross.addPoint(-minxy6, y2);
cross.addPoint(-minxy6, minxy6);
cross.addPoint(-x2, minxy6);
cross.addPoint(-x2, -minxy6);
cross.addPoint(-minxy6, -minxy6);
cross.addPoint(-minxy6, -y2);
return cross;
case X: // TODO IMPLEMENT
Polygon xShape = new Polygon();
xShape.addPoint(0, -minxy6);
xShape.addPoint(x2 - minxy6, - y2);
xShape.addPoint(x2, - y2 +minxy6);
xShape.addPoint(minxy6, 0);
xShape.addPoint(x2, y2 - minxy6);
xShape.addPoint(x2 - minxy6, y2);
xShape.addPoint(0, minxy6);
xShape.addPoint(- x2 + minxy6, y2);
xShape.addPoint(- x2, y2 - minxy6);
xShape.addPoint(-minxy6, 0);
xShape.addPoint(- x2, - y2 +minxy6);
xShape.addPoint(- x2 + minxy6, - y2);
xShape.addPoint(0, -minxy6);
return xShape;
case SQUARE:
default:
return new Rectangle2D.Double(-Math.abs(x2), -Math.abs(y2), Math.abs(x), Math.abs(y));
}
}
@Override
public double getDefaultMaxWidth(Map<String,Object> map,
Double scale, Double dpi, RealParameter markIndex, String mimeType) {
return DEFAULT_SIZE;
}
}