/**
* Copyright 2010-2013 Jingjing Li.
*
* This file is part of jplot2d.
*
* jplot2d 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, either version 3 of the
* License, or any later version.
*
* jplot2d 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 Lesser Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with jplot2d. If not, see .
*/
package org.jplot2d.util;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.jplot2d.javacc.ParseException;
import org.jplot2d.javacc.SymbolShapeParser;
import org.jplot2d.javacc.TokenMgrError;
/**
* SymbolShape has an unique name and data to direct how to paint it.
*
* The instance is immutable! This class also maintains a internal collection to keep all created symbol shapes. User
* can call the static method {@link #getSymbolShapes()} to get them.
*
* A symbol is painted in an 1-unit circle boundary. The data syntax (in EBNF):
*
*
* syntax = "{" SHAPE+ "}"
* SHAPE = FILLEDSHAPE | OUTLINESHAPE
* FILLEDSHAPE = "F" SHAPEDESC
* OUTLINESHAPE = SHAPEDESC
* SHAPEDESC = LINE | ARC | CIRCLE | ELLIPSE | RECTANGLE | POLYGON
* LINE = "L" LINE_DATA
* LINE_DATA = POINT POINT
* ARC = OPENARC | CHORDARC | PIEARC
* OPENARC = "A" ARC_DARTA
* CHORDARC = "AC" ARC_DARTA
* PIEARC = "AP" ARC_DARTA
* ARC_DARTA = RECTANGLE_DATA ANGLERANGE
* ANGLERANGE = "(" NUM "," NUM ")"
* CIRCLE = "C" CIRCLE_DATA
* CIRCLE_DATA = "(" NUM "," NUM "," NUM ")"
* ELLIPSE = "E" RECTANGLE_DATA
* RECTANGLE = "R" RECTANGLE_DATA
* RECTANGLE_DATA = DIAGONAL_DATA | XYWH_DATA
* DIAGONAL_DATA = LINE_DATA
* XYWH_DATA = "(" NUM "," NUM "," NUM "," NUM ")"
* POLYGON = "P" POINT POINT POINT+
* POINT = "(" NUM "," NUM ")"
* NUM = ("+"|"-")? (["0"-"9"])+ ("." (["0"-"9"])*)? | "." (["0"-"9"])*
*
*
*
*
RECTANGLE
* is represented by a pair of end points of a diagonal or by x,y of bottom left corner point and width and height.
* ELLIPSE
* is represented by a bounding RECTANGLE.
* CIRLE
* is represented by a center point and radius.
* ARC
* is represented by a ELLIPSE bounding rectangle and a ANGLERANGE, which is defined by starting angle and angular
* extent in degrees.
*
*
*
* @author Jingjing Li
*
*/
public class SymbolShape {
private static final Map _symbolMap = new LinkedHashMap();
private static final ThreadLocal parserTL = new ThreadLocal() {
@Override
protected SymbolShapeParser initialValue() {
return new SymbolShapeParser(new StringReader(""));
}
};
public static final SymbolShape VCROSS = createSymbolShape("VCROSS", "{L(-0.5,0)(0.5,0) L(0,-0.5)(0,0.5)}");
public static final SymbolShape DCROSS = createSymbolShape("DCROSS",
"{L(-0.707,-0.707)(0.707,0.707) L(-0.707,0.707)(0.707,-0.707)}");
public static final SymbolShape VDCROSS = createSymbolShape("VDCROSS",
"{L(-0.5,0)(0.5,0) L(0,-0.5)(0,0.5) L(-0.707,-0.707)(0.707,0.707) L(-0.707,0.707)(0.707,-0.707)}");
public static final SymbolShape CIRCLE = createSymbolShape("CIRCLE", "{C(0,0,0.5)}");
public static final SymbolShape FCIRCLE = createSymbolShape("FCIRCLE", "{FC(0,0,0.5)}");
public static final SymbolShape TRIANGLE = createSymbolShape("TRIANGLE", "{P(-0.433,-0.25)(0.433,-0.25)(0,0.5)}");
public static final SymbolShape FTRIANGLE = createSymbolShape("FTRIANGLE", "{FP(-0.433,-0.25)(0.433,-0.25)(0,0.5)}");
public static final SymbolShape UTRIANGLE = createSymbolShape("UTRIANGLE", "{P(-0.433,0.25)(0.433,0.25)(0,-0.5)}");
public static final SymbolShape SQUARE = createSymbolShape("SQUARE", "{R(-0.354,-0.354)(0.354,0.354)}");
public static final SymbolShape FSQUARE = createSymbolShape("FSQUARE", "{FR(-0.354,-0.354)(0.354,0.354)}");
public static final SymbolShape SQUARE_CROSS = createSymbolShape("SQUARE_CROSS",
"{R(-0.354,-0.354)(0.354,0.354) L(-0.354,-0.354)(0.354,0.354) L(-0.354,0.354)(0.354,-0.354)}");
public static final SymbolShape DIAMOND = createSymbolShape("DIAMOND", "{P(-0.5,0)(0,-0.5)(0.5,0)(0,0.5)}");
public static final SymbolShape FDIAMOND = createSymbolShape("FDIAMOND", "{FP(-0.5,0)(0,-0.5)(0.5,0)(0,0.5)}");
public static final SymbolShape DIAMOND_CROSS = createSymbolShape("DIAMOND_CROSS",
"{P(-0.5,0)(0,-0.5)(0.5,0)(0,0.5) L(-0.5,0)(0.5,0) L(0,-0.5)(0,0.5)}");
public static final SymbolShape OCTAGON = createSymbolShape(
"OCTAGON",
"{P(-0.4619,-0.1913)(-0.1913,-0.4619)(0.1913,-0.4619)(0.4619,-0.1913)(0.4619,0.1913)(0.1913,0.4619)(-0.1913,0.4619)(-0.4619,0.1913)}");
public static final SymbolShape FOCTAGON = createSymbolShape(
"FOCTAGON",
"{FP(-0.4619,-0.1913)(-0.1913,-0.4619)(0.1913,-0.4619)(0.4619,-0.1913)(0.4619,0.1913)(0.1913,0.4619)(-0.1913,0.4619)(-0.4619,0.1913)}");
public static final SymbolShape STAR = createSymbolShape("STAR",
"{P(-0.4755,0.1545)(0.4755,0.1545)(-0.2939,-0.4045)(0,0.5)(0.2939,-0.4045)}");
public static final SymbolShape UARROW = createSymbolShape("UARROW",
"{L(0,-0.5)(0,0) L(0,0)(-0.25,-0.25) L(0,0)(0.25,-0.25)}");
public static final SymbolShape DARROW = createSymbolShape("DARROW",
"{L(0,0.5)(0,0) L(0,0)(-0.25,0.25) L(0,0)(0.25,0.25)}");
public static final SymbolShape RARROW = createSymbolShape("RARROW",
"{L(-0.5,0)(0,0) L(0,0)(-0.25,0.25) L(0,0)(-0.25,-0.25)}");
public static final SymbolShape LARROW = createSymbolShape("LARROW",
"{L(0.5,0)(0,0) L(0,0)(0.25,-0.25) L(0,0)(0.25,0.25)}");
public static final SymbolShape UARROW_TAIL = createSymbolShape("UARROW_TAIL",
"{L(0,0)(0,0.5) L(0,0.5)(-0.25,0.25) L(0,0.5)(0.25,0.25)}");
public static final SymbolShape DARROW_TAIL = createSymbolShape("DARROW_TAIL",
"{L(0,0)(0,-0.5) L(0,-0.5)(-0.25,-0.25) L(0,-0.5)(0.25,-0.25)}");
public static final SymbolShape RARROW_TAIL = createSymbolShape("RARROW_TAIL",
"{L(0,0)(0.5,0) L(0.5,0)(0.25,0.25) L(0.5,0)(0.25,-0.25)}");
public static final SymbolShape LARROW_TAIL = createSymbolShape("LARROW_TAIL",
"{L(0,0)(-0.5,0) L(-0.5,0)(-0.25,-0.25) L(-0.5,0)(-0.25,0.25)}");
/**
* Returns all symbol shapes in a array.
*
* @return a array contains all symbol shapes.
*/
public static SymbolShape[] getSymbolShapes() {
synchronized (_symbolMap) {
return _symbolMap.values().toArray(new SymbolShape[_symbolMap.size()]);
}
}
// =========================================================
private String name;
private String data;
protected final List drawShapeList = new ArrayList();
protected final List fillShapeList = new ArrayList();
/**
* Create a symbol with a name and a description string
*
* @param name
* @param data
* the shape description string
*/
public static SymbolShape createSymbolShape(String name, String data) {
SymbolShape ss = new SymbolShape(name, data);
synchronized (_symbolMap) {
_symbolMap.put(name, ss);
}
return ss;
}
/**
* Create a symbol with a name and a description string
*
* @param name
* @param data
* the shape description string
*/
protected SymbolShape(String name, String data) {
if (name.indexOf('{') != -1) {
throw new IllegalArgumentException("The char '{' is not allowed in name.");
}
this.name = name;
this.data = data;
this.parseData(data);
}
/**
* Returns the symbol name
*
* @return the symbol name
*/
public String getName() {
return name;
}
/**
* Returns the data string of this SymbolShape
*
* @return the data string
*/
public String getData() {
return data;
}
/**
* Transform this shape and drawing it to the given Graphics2D.
*
* @param g
* the graphics context to use for drawing
* @param maf
* the AffineTransform that transform this shape before drawing
*/
public void draw(Graphics2D g, AffineTransform maf) {
Iterator dit = drawShapeList.iterator();
while (dit.hasNext()) {
Shape s = maf.createTransformedShape(dit.next());
g.draw(s);
}
Iterator fit = fillShapeList.iterator();
while (fit.hasNext()) {
Shape s = maf.createTransformedShape(fit.next());
g.fill(s);
}
}
protected void parseData(String data) {
if (data == null || data.length() == 0) {
throw new IllegalArgumentException("data cannot be null or empty");
}
SymbolShapeParser ssp = parserTL.get();
try {
ssp.parse(data);
drawShapeList.addAll(ssp.getDrawShapeList());
fillShapeList.addAll(ssp.getFillShapeList());
} catch (ParseException e) {
throw new IllegalArgumentException("the syntax of data is not correct", e);
} catch (TokenMgrError e) {
throw new IllegalArgumentException("the syntax of data is not correct", e);
}
}
public boolean equals(Object obj) {
return obj instanceof SymbolShape && name == ((SymbolShape) obj).name;
}
public int hashCode() {
return name.hashCode();
}
public String toString() {
return name;
}
}
Ads help maintain this website.