package ini.trakem2.utils;
import java.awt.geom.Area;
import java.awt.geom.GeneralPath;
/** Reconstruct an Area from a list of XML <t2_path d="M ... z"/> entries. */
public final class ReconstructArea {
private final GeneralPath gp = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
/** To reconstruct from XML, takes a "M .... z" SVG path. */
public final void add(String svg_path) {
// Ensure format
svg_path = svg_path.trim();
while (-1 != svg_path.indexOf(" ")) {
svg_path = svg_path.replaceAll(" "," "); // make all spaces be single
}
// parse according to assumptions
final char[] data = new char[svg_path.length()];
svg_path.getChars(0, data.length, data, 0);
parse(gp, data);
}
public final Area getArea() {
return new Area(gp);
}
public final GeneralPath getGeneralPath() {
return gp;
}
/** Assumes first char is 'M' and last char is a 'z'*/
static private final void parse(final GeneralPath gp, final char[] data) {
if ('z' != data[data.length-1]) {
Utils.log("AreaList: no closing z, ignoring sub path");
return;
}
data[data.length-1] = 'L'; // replacing the closing z for an L, since we read backwards
final float[] xy = new float[2];
int i_L = -1;
// find first L
for (int i=0; i<data.length; i++) {
if ('L' == data[i]) {
i_L = i;
break;
}
}
readXY(data, i_L, xy);
//final float x0 = xy[0];
//final float y0 = xy[1];
//gp.moveTo(x0, y0);
gp.moveTo(xy[0], xy[1]);
int first = i_L+1;
while (-1 != (first = readXY(data, first, xy))) {
gp.lineTo(xy[0], xy[1]);
}
// close loop
//gp.lineTo(x0, y0); //TODO unnecessary?
gp.closePath();
}
/** Assumes all read chars will be digits except for the separator (single white space char), and won't fail (but generate ugly results) when any char is not a digit. */
static public final int readXY(final char[] data, int first, final float[] xy) { // final method: inline
if (first >= data.length) return -1;
int last = first;
char c = data[first];
while ('L' != c) {
last++;
if (data.length == last) return -1;
c = data[last];
}
first = last +2; // the first digit position after the found L (the found L will be the next first)
// skip the L and the white space separating <y> and L
last -= 2;
if (last < 0) return -1;
c = data[last];
// the 'y'
xy[1] = 0;
int pos = 1;
while (' ' != c) {
last--;
if ('-' == c) {
xy[1] *= -1;
break;
} else if ('.' == c) {
// divide by position to make all numbers be after the comma
xy[1] /= pos;
pos = 1;
} else {
xy[1] += (((int)c) -48) * pos; // digit zero is char with int value 48
pos *= 10;
}
c = data[last];
}
// skip separating space
last--;
// the 'x'
c = data[last];
pos = 1;
xy[0] = 0;
while (' ' != c) {
last--;
if ('-' == c) {
xy[0] *= -1;
break;
} else if ('.' == c) {
// divide by position to make all numbers be after the comma
xy[0] /= pos;
pos = 1;
} else {
xy[0] += (((int)c) -48) * pos;
pos *= 10;
}
c = data[last];
}
return first;
}
}