FileDocCategorySizeDatePackage
Path.javaAPI DocphoneME MR2 API (J2ME)17638Wed May 02 18:00:34 BST 2007com.sun.perseus.j2d

Path

public class Path extends Object implements org.w3c.dom.svg.SVGPath
Class for Path Data.
version
$Id: Path.java,v 1.7 2006/04/21 06:35:11 st125089 Exp $

Fields Summary
public static final int
WIND_EVEN_ODD
The event-odd winding rule.
public static final int
WIND_NON_ZERO
The non-zero winding rule.
static final int
INITIAL_COMMAND_CAPACITY
The default initial number of commands.
static final int
INITIAL_DATA_CAPACITY
The default initial number of data entries.
public static final byte
MOVE_TO_IMPL
The internal value for moveTo commands.
public static final byte
LINE_TO_IMPL
The internal value for lineTo commands
public static final byte
QUAD_TO_IMPL
The internal value for quadTo commands
public static final byte
CURVE_TO_IMPL
The internal value for curveTo commands.
public static final int
CLOSE_IMPL
The internal value for close commands.
public static final int[]
COMMAND_OFFSET
Delta offset for each command type. 2 for moveto and lineto. 4 for quadto. 6 for curveto. 0 for close.
protected byte[]
commands
An array storing the path command types. One of MOVE_TO_IMPL, LINE_TO_IMPL, QUAD_TO_IMPL, CURVE_TO_IMPL.
protected float[]
data
An array storing the path data. The array is a list of even length made of consecutive x/y coordinate pairs.
protected int
nSegments
The current number of segments.
protected int
nData
The number of used entries in the data array.
protected int
lastCmdIndex
Keeps track of the last requested command index.
protected int
lastOffset
The offset in the data array for the last requested command. This is used to minimize the computation of the offset in getSegmentParam.
Constructors Summary
public Path()
Default constructor. The initial capacity is defined by the INITIAL_COMMAND_CAPACITY and INITIAL_DATA_CAPACITY static variables.

        this(INITIAL_COMMAND_CAPACITY, INITIAL_DATA_CAPACITY);
    
public Path(int commandCapacity, int dataCapacity)
Initial constructor. The initial capacity is defined by the capacity parameters.

param
commandCapacity the number of intended commands for this object. Must be positive or zero.
param
dataCapacity the number of intended data parameters for this object. Must be positive or zero.

        commands = new byte[commandCapacity];
        data = new float[dataCapacity];
    
public Path(Path model)
Copy constructor.

param
model the Path object to duplicate.

        if (model != null) {
            // Copy path data.
            this.data = new float[model.data.length];
            System.arraycopy(model.data, 0, data, 0, model.data.length);
            
            // Copy command data
            this.commands = new byte[model.commands.length];
            System.arraycopy(model.commands, 0, commands, 0, model.commands.length);
            
            this.nData = model.nData;
            this.nSegments = model.nSegments;
        } // else, use default values
    
Methods Summary
final intcheckOffset(int cmdIndex)
Implementation helper. Sets the lastCmdIndex to the requested index after computing the offset corresponding to that index.

param
cmdIndex the new index for which the offset should be computed.

        if (cmdIndex == lastCmdIndex) {
            return lastOffset;
        }

        if (cmdIndex > lastCmdIndex) {
            // The new index is _after_ the previous one. Add offsets for all
            // commands between the two indices.
            for (int ci = lastCmdIndex; ci < cmdIndex; ci++) {
                lastOffset += COMMAND_OFFSET[commands[ci]];
            }
        } else {
            // The next index is _before_ the previous one. Remove offsets for
            // all commands, between the two indices.
            for (int ci = lastCmdIndex - 1; ci >= cmdIndex; ci--) {
                lastOffset -= COMMAND_OFFSET[commands[ci]];
            }
        }

        lastCmdIndex = cmdIndex;
        return lastOffset;
    
public voidclose()

        newCommand(0);
        commands[nSegments] = CLOSE_IMPL;

        nSegments++;
    
public voidcurveTo(float x1, float y1, float x2, float y2, float x3, float y3)

        newCommand(3);
        commands[nSegments] = CURVE_TO_IMPL;

        data[nData] = x1;
        data[nData + 1] = y1;
        data[nData + 2] = x2;
        data[nData + 3] = y2;
        data[nData + 4] = x3;
        data[nData + 5] = y3;

        nSegments++;
        nData += 6;
    
public booleanequals(java.lang.Object obj)

return
true if obj is a path and all its commands are the same as this instance.

        if (obj == this) {
            return true;
        }

        if (obj == null || !(obj instanceof Path)) {
            return false;
        }

        Path p = (Path) obj;
        if (nSegments != p.nSegments || nData != nData) {
            return false;
        }

        // Compare each command type and offset
        for (int ci = 0; ci < nSegments; ci++) {
            // Check we are dealing with the same command type
            if (commands[ci] != p.commands[ci]) {
                return false;
            }
        }

        // Now, compare each command data
        for (int di = 0; di < nData; di++) {
            if (data[di] != p.data[di]) {
                return false;
            }
        }

        return true;
    
public BoxgetBounds()
Compute the path's bounds.

return
the path's bounds.

        float x1, y1, x2, y2;
        int i = nData - 2;
        if (nData > 0) {
            x1 = x2 = data[i];
            y1 = y2 = data[i + 1];
            i -= 2;
            while (i >= 0) {
                float x = data[i];
                float y = data[i + 1];
                i -= 2;
                if (x < x1) x1 = x;
                if (y < y1) y1 = y;
                if (x > x2) x2 = x;
                if (y > y2) y2 = y;
            }
        } else {
            x1 = y1 = x2 = y2 = 0.0f;
        }
        
        return new Box(x1, y1, x2 - x1, y2 - y1);
    
public byte[]getCommands()

return
this path's commands data.

        return commands;
    
public float[]getData()

return
this path's data.

        return data;
    
public intgetNumberOfSegments()


         
       
        return nSegments;
    
public shortgetSegment(int cmdIndex)

        if (cmdIndex >= nSegments || cmdIndex < 0) {
            throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
        }

        return toSVGPathCommand(commands[cmdIndex]);
    
public floatgetSegmentParam(int cmdIndex, int paramIndex)

        if (cmdIndex >= nSegments || cmdIndex < 0 || paramIndex < 0) {
            throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
        }

        switch (commands[cmdIndex]) {
        case CLOSE_IMPL:
            throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
        case LINE_TO_IMPL:
        case MOVE_TO_IMPL:
            if (paramIndex > 1) {
                throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
            }
            break;
        case QUAD_TO_IMPL:
            if (paramIndex > 3) {
                throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
            }
            break;
        case CURVE_TO_IMPL:
            if (paramIndex > 5) {
                throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
            }
            break;
        default:
            throw new DOMException(DOMException.INDEX_SIZE_ERR, "");
        }

        return data[checkOffset(cmdIndex) + paramIndex];
    
public BoxgetTransformedBounds(Transform t)
Compute the path's bounds in the transformed coordinate system.

        float x1, y1, x2, y2;
        int i = nData - 2;
        float x0, y0, x, y;
        if (nData > 0) {
            x0 = data[i];
            y0 = data[i + 1];
            x1 = x2 = x0 * t.m0 + y0 * t.m2 + t.m4;
            y1 = y2 = x0 * t.m1 + y0 * t.m3 + t.m5;
            i -= 2;
            while (i >= 0) {
                x0 = data[i];
                y0 = data[i + 1];
                i -= 2;
                x = x0 * t.m0 + y0 * t.m2 + t.m4;
                y = x0 * t.m1 + y0 * t.m3 + t.m5;
                if (x < x1) x1 = x;
                if (y < y1) y1 = y;
                if (x > x2) x2 = x;
                if (y > y2) y2 = y;
            }
        } else {
            x1 = y1 = x2 = y2 = 0.0f;
        }
        
        return new Box(x1, y1, x2 - x1, y2 - y1);
    
public voidlineTo(float x, float y)

        newCommand(1);
        commands[nSegments] = LINE_TO_IMPL;
        data[nData] = x;
        data[nData + 1] = y;

        nSegments++;
        nData += 2;
    
public voidmoveTo(float x, float y)

        newCommand(1);
        commands[nSegments] = MOVE_TO_IMPL;
        data[nData] = x;
        data[nData + 1] = y;

        nSegments++;
        nData += 2;
    
voidnewCommand(int nPoints)
Adjust the internal arrays for the requested number of points.

param
nParams the number of points to add to the array.

        // Adjust the length of the command array if needed.
        if (nSegments == commands.length) {
            byte[] tmpCommands = new byte[commands.length * 2 + 1];
            System.arraycopy(commands, 0, tmpCommands, 0, commands.length);
            commands = tmpCommands;
        }

        // Adjust the length of the data array if needed.
        if (nData + nPoints * 2 > data.length) {
            float[] tmpData = new float[(nData + nPoints * 2) * 2];
            System.arraycopy(data, 0, tmpData, 0, data.length);
            data = tmpData;
        }
    
public voidquadTo(float x1, float y1, float x2, float y2)

        newCommand(2);
        commands[nSegments] = QUAD_TO_IMPL;
        data[nData] = x1;
        data[nData + 1] = y1;
        data[nData + 2] = x2;
        data[nData + 3] = y2;

        nSegments++;
        nData += 4;
     
public voidsetData(float[] newData)

param
newData the new path data. The Path is only guaranteed to work after this method is invoked if the input data array has at least as many entries as the current path data array and if each entry is a float array of at least two values.

        if (nData == 0) {
            return;
        }

        this.data = newData;
    
public java.lang.StringtoPointsString()

return
a string descriton of this Path using the points syntax. This methods throws an IllegalStateException if the path does not have the commands corresponding to the points syntax (initial move to followed by linetos and closes

        return toPointsString(data);
    
public java.lang.StringtoPointsString(float[] d)

param
d the set of data values to use for the string conversion. This will fail if the input data array does not have an even number of values.
return
a string descriton of this Path using the points syntax. This methods throws an IllegalStateException if the path does not have the commands corresponding to the points syntax (initial move to followed by linetos and closes

        StringBuffer sb = new StringBuffer();
        int curSegment = 0;
        int off = 0, cmd = 0;

        while (curSegment < nSegments) {
            switch(commands[curSegment]) {
            case Path.MOVE_TO_IMPL:
                if (curSegment > 0) {
                    throw new IllegalArgumentException();
                }
                sb.append(d[off]);
                sb.append(',");
                sb.append(d[off + 1]);
                sb.append(' ");
                off += 2;
                break;
            case Path.LINE_TO_IMPL:
                sb.append(d[off]);
                sb.append(',");
                sb.append(d[off + 1]);
                sb.append(' ");
                off += 2;
                break;
            case Path.CLOSE_IMPL:
                break;
            default:
            case Path.QUAD_TO_IMPL:
            case Path.CURVE_TO_IMPL:
                throw new IllegalArgumentException();
            }
            
            curSegment++;
        }
        return sb.toString().trim();
    
static shorttoSVGPathCommand(int command)

        switch (command) {
        case MOVE_TO_IMPL:
            return SVGPath.MOVE_TO;
        case LINE_TO_IMPL:
            return SVGPath.LINE_TO;
        case QUAD_TO_IMPL:
            return SVGPath.QUAD_TO;
        case CURVE_TO_IMPL:
            return SVGPath.CURVE_TO;
        case CLOSE_IMPL:
        default:
            return SVGPath.CLOSE;
        }
    
public java.lang.StringtoString()

return
a String representation of this path, using the SVG notation.

        return toString(data);
    
public java.lang.StringtoString(float[] d)

param
d the set of data values to use for the string conversion. This will fail if the input data array does not have at least nData entries of at least 2 values.
return
a String representation of this path, using the SVG notation.

        StringBuffer sb = new StringBuffer();
        int offset = 0;
        for (int i = 0; i < nSegments; i++) {
            switch (commands[i]) {
            case Path.MOVE_TO_IMPL:
                sb.append('M");
                sb.append(d[offset]);
                sb.append(',");
                sb.append(d[offset + 1]);
                offset += 2;
                break;
            case Path.LINE_TO_IMPL:
                sb.append('L");
                sb.append(d[offset]);
                sb.append(',");
                sb.append(d[offset + 1]);
                offset += 2;
                break;
            case Path.QUAD_TO_IMPL:
                sb.append('Q");
                sb.append(d[offset]);
                sb.append(',");
                sb.append(d[offset + 1]);
                sb.append(',");
                sb.append(d[offset + 2]);
                sb.append(',");
                sb.append(d[offset + 3]);
                offset += 4;
                break;
            case Path.CURVE_TO_IMPL:
                sb.append('C");
                sb.append(d[offset]);
                sb.append(',");
                sb.append(d[offset + 1]);
                sb.append(',");
                sb.append(d[offset + 2]);
                sb.append(',");
                sb.append(d[offset + 3]);
                sb.append(',");
                sb.append(d[offset + 4]);
                sb.append(',");
                sb.append(d[offset + 5]);
                offset += 6;
                break;
            case Path.CLOSE_IMPL:
                sb.append('Z");
                break;
            default:
                throw new Error();
            }
        }

        return sb.toString();