/*
* @(#)ShapeStringUtils.java
*
* $Date: 2014-03-13 09:15:48 +0100 (Cs, 13 márc. 2014) $
*
* Copyright (c) 2011 by Jeremy Wood.
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* Jeremy Wood. For details see accompanying license terms.
*
* This software is probably, but not necessarily, discussed here:
* https://javagraphics.java.net/
*
* That site should also contain the most recent official version
* of this software. (See the SVN repository for more details.)
*/
package com.bric.geom;
import java.awt.Shape;
import java.awt.geom.GeneralPath;
import java.awt.geom.PathIterator;
/** This is a small set of static methods that translate shape data into
* <code>java.lang.Strings</code> and vice versa.
*
*
*/
public class ShapeStringUtils {
/** This describes a shape in a <code>String</code>. The model is used
* is based on how SVG encodes shape data.
* <P>The call:
* <BR><code>ShapeUtils.createPathIterator(ShapeUtils.toString(shape));</code>
* <BR>should result in an identical shape.
* <P>The shape data is formatted as a single letter (m, l, q, c, z)
* followed by the appropriate number of points (2, 2, 4, 6, 0 respectively).
* This uses floats, not doubles, so it will not contain strings with an exponent
* (i.e. "1.3e-4").
* @param s the shape to describe
* @return textual representation of that shape.
*/
public static String toString(Shape s) {
PathIterator i = s.getPathIterator(null);
return toString(i);
}
public static String toString(PathIterator i) {
float[] f = new float[6];
//TODO: didn't you read once that a string buffer
//is a little inefficient?
StringBuffer sb = new StringBuffer();
int k;
int j = 0;
while(i.isDone()==false) {
k = i.currentSegment(f);
if(k==PathIterator.SEG_MOVETO) {
sb.append('m');
j = 2;
} else if(k==PathIterator.SEG_LINETO) {
sb.append('l');
j = 2;
} else if(k==PathIterator.SEG_QUADTO) {
sb.append('q');
j = 4;
} else if(k==PathIterator.SEG_CUBICTO) {
sb.append('c');
j = 6;
} else if(k==PathIterator.SEG_CLOSE) {
sb.append('z');
j = 0;
}
if(j!=0) {
sb.append(' ');
for(int a = 0; a<j; a++) {
sb.append(Float.toString(f[a]));
if(a<j-1)
sb.append(' ');
}
}
i.next();
if(i.isDone()==false)
sb.append(' ');
}
return sb.toString();
}
/** This creates a <code>PathIterator</code> that iterates
* over the text in <code>s</code>.
* <P>The shape returned uses winding rule WIND_EVEN_ODD.
* @param s textual representation of a path.
* <P>This should be the output of <code>ShapeUtils.toString()</code>,
* resembling: "m 1 2 l 3 4 q 5 6 7 8 c 9 10 11 12 13 14 z"
* @return a <code>PathIterator</code> that will iterate over the data in s.
*/
public static PathIterator createPathIterator(String s) {
return createPathIterator(s,PathIterator.WIND_EVEN_ODD);
}
/** This creates a <code>GeneralPath</code> of rule WIND_EVEN_ODD
* that represents this shape data.
* <P>This method simply calls:
* <BR><code>GeneralPath p = new GeneralPath();</code>
* <BR><code>p.append(createPathIterator(s),true);</code>
* <BR><code>return p;</code>
*
* @param s textual representation of a path.
* <P>This should be the output of <code>ShapeUtils.toString()</code>,
* resembling: "m 1 2 l 3 4 q 5 6 7 8 c 9 10 11 12 13 14 z"
* @return a <code>GeneralPath</code> that represents this shape.
*/
public static GeneralPath createGeneralPath(String s) {
GeneralPath p = new GeneralPath();
p.append(createPathIterator(s),true);
return p;
}
/** This creates a <code>PathIterator</code> that iterates
* over the text in <code>s</code>.
* @param s textual representation of a path.
* @param windingRule the winding rule to use.
* (This should be PathIterator.WIND_NON_ZERO or PathIterator.WIND_EVEN_ODD.)
* <P>This should be the output of <code>ShapeUtils.toString()</code>,
* resembling: "m 1 2 l 3 4 q 5 6 7 8 c 9 10 11 12 13 14 z"
* @return a <code>PathIterator</code> that will iterate over the data in s.
*/
public static PathIterator createPathIterator(String s,int windingRule) {
/** This little bit is added so if the string passed resembles:
* "Data[ m 34 20 l 20 10 z ]"
* Then we focus only on the part in brackets.
*/
int i1 = s.indexOf('[');
int i2 = s.indexOf(']');
if(i1!=-1 && i2!=-2 && i1<i2) {
s = s.substring(i1+1,i2);
}
return new SerializedPathIterator(s,PathIterator.WIND_EVEN_ODD);
}
}