From: adam Date: Mon, 3 May 2004 00:53:38 +0000 (+0000) Subject: added smoother vectorization to Path.java, did some reorg X-Git-Tag: 01-July-2005~42 X-Git-Url: http://git.megacz.com/?a=commitdiff_plain;h=b68065b68711c015662a7bf9c2e27c43a4d9ddb3;hp=545a6bc7e6aff46ecb6012648fd9dd6f02588166;p=org.ibex.core.git added smoother vectorization to Path.java, did some reorg darcs-hash:20040503005338-5007d-170aabbc75ccc7640d0248ebe6465bca7a7e0090.gz --- diff --git a/src/org/ibex/graphics/Path.java b/src/org/ibex/graphics/Path.java index 1e5c79f..4340015 100644 --- a/src/org/ibex/graphics/Path.java +++ b/src/org/ibex/graphics/Path.java @@ -5,6 +5,7 @@ // FIXME package org.ibex.graphics; import java.util.*; +import org.ibex.util.*; /** an abstract path; may contain splines and arcs */ public class Path { @@ -39,7 +40,59 @@ public class Path { static final byte TYPE_CUBIC = 3; static final byte TYPE_QUADRADIC = 4; - public static Path parse(String s) { return Tokenizer.parse(s); } + // FIXME: hack + private String toString; + public String toString() { return toString; } + + public Path(String s) { + this.toString = s; + Tokenizer t = new Tokenizer(s); + char last_command = 'M'; + boolean first = true; + while(t.hasMoreTokens()) { + char command = t.parseCommand(); + if (first && command == 'm') command = 'M'; + if (first && command != 'M') throw new RuntimeException("the first command of a path must be 'M'"); + first = false; + boolean relative = Character.toLowerCase(command) == command; + command = Character.toLowerCase(command); + parseSingleCommandAndArguments(t, command, relative); + last_command = command; + } + } + + public long transform(Affine a, boolean forReal) { return transform(a, forReal, true); } + public long transform(Affine a, boolean forReal, boolean widthheight) { + float minx = Integer.MAX_VALUE; float miny = Integer.MAX_VALUE; + float maxx = Integer.MIN_VALUE; float maxy = Integer.MIN_VALUE; + for(int i=0; imaxx) maxx = x; if (xmaxy) maxy = y; if (ymaxx) maxx = c1x; if (c1xmaxy) maxy = c1y; if (c1ymaxx) maxx = c2x; if (c2xmaxy) maxy = c2y; if (c2y 0) ret.sort(0, ret.numedges - 1, false); - return ret; + } finally { Scheduler.rasterizing += System.currentTimeMillis() - start; } } protected void parseSingleCommandAndArguments(Tokenizer t, char command, boolean relative) { - if (numvertices == 0 && command != 'm') throw new RuntimeException("first command MUST be an 'm'"); + if (numvertices == 0 && command != 'm') + throw new RuntimeException("first command MUST be an 'm', not a " + command); if (numvertices > x.length - 2) { float[] new_x = new float[x.length * 2]; System.arraycopy(x, 0, new_x, 0, x.length); x = new_x; float[] new_y = new float[y.length * 2]; System.arraycopy(y, 0, new_y, 0, y.length); y = new_y; @@ -246,12 +304,12 @@ public class Path { case 'z': { int where; type[numvertices-1] = TYPE_LINETO; - for(where = numvertices - 1; where > 0; where--) - if (type[where - 1] == TYPE_MOVETO) break; - x[numvertices] = x[where]; - y[numvertices] = y[where]; + for(where = numvertices-2; where >= 0 && type[where] != TYPE_MOVETO; where--); + x[numvertices] = x[where+1]; + y[numvertices] = y[where+1]; numvertices++; closed = true; + // FIXME: actually, we should search back to the last 'z' or 'm', not just 'm' break; } @@ -259,7 +317,12 @@ public class Path { if (numvertices > 0) type[numvertices-1] = TYPE_MOVETO; x[numvertices] = t.parseFloat() + (relative ? x[numvertices - 1] : 0); y[numvertices] = t.parseFloat() + (relative ? y[numvertices - 1] : 0); - numvertices++; + if (numvertices > 2 && type[numvertices-2] == TYPE_MOVETO) { + x[numvertices-1] = x[numvertices]; + y[numvertices-1] = y[numvertices]; + } else { + numvertices++; + } break; } @@ -368,180 +431,4 @@ public class Path { } - - // Rasterized Vector Path ////////////////////////////////////////////////////////////////////////////// - - /** a vector path */ - public static class Raster { - - // the vertices of this path - int[] x = new int[DEFAULT_PATHLEN]; - int[] y = new int[DEFAULT_PATHLEN]; - int numvertices = 0; - - /** - * A list of the vertices on this path which *start* an *edge* (rather than a moveto), sorted by increasing y. - * example: x[edges[1]],y[edges[1]] - x[edges[i]+1],y[edges[i]+1] is the second-topmost edge - * note that if x[i],y[i] - x[i+1],y[i+1] is a MOVETO, then no element in edges will be equal to i - */ - int[] edges = new int[DEFAULT_PATHLEN]; - int numedges = 0; - - /** translate a rasterized path */ - public void translate(int dx, int dy) { for(int i=0; i left && y[edges[--j]] > y[edges[right]]); - if (i >= j) break; - s = edges[i]; edges[i] = edges[j]; edges[j] = s; - } - s = edges[right]; edges[right] = edges[i]; edges[i] = s; - return i; - } else { - if (left >= right) return 0; - int p = sort(left, right, true); - sort(left, p - 1, false); - sort(p + 1, right, false); - return 0; - } - } - - /** finds the x value at which the line intercepts the line y=_y */ - private int intercept(int i, float _y, boolean includeTop, boolean includeBottom) { - if (includeTop ? (_y < Math.min(y[i], y[i+1])) : (_y <= Math.min(y[i], y[i+1]))) - return Integer.MIN_VALUE; - if (includeBottom ? (_y > Math.max(y[i], y[i+1])) : (_y >= Math.max(y[i], y[i+1]))) - return Integer.MIN_VALUE; - return (int)Math.round((((float)(x[i + 1] - x[i])) / - ((float)(y[i + 1] - y[i])) ) * ((float)(_y - y[i])) + x[i]); - } - - /** fill the interior of the path */ - public void fill(PixelBuffer buf, Paint paint) { - if (numedges == 0) return; - int y0 = y[edges[0]], y1 = y0; - boolean useEvenOdd = false; - - // we iterate over all endpoints in increasing y-coordinate order - for(int index = 1; index x1) continue; - if (midpoint == x1 && i >= rightSegment) continue; - rightSegment = i; - x1 = midpoint; - } - if (leftSegment == rightSegment || rightSegment == Integer.MAX_VALUE) break; - if (leftSegment != -1) - if ((useEvenOdd && count % 2 != 0) || (!useEvenOdd && count != 0)) - paint.fillTrapezoid(intercept(edges[leftSegment], y0, true, true), - intercept(edges[rightSegment], y0, true, true), y0, - intercept(edges[leftSegment], y1, true, true), - intercept(edges[rightSegment], y1, true, true), y1, - buf); - if (useEvenOdd) count++; - else count += (y[edges[rightSegment]] < y[edges[rightSegment]+1]) ? -1 : 1; - leftSegment = rightSegment; x0 = x1; - } - } - } - - /** stroke the outline of the path */ - public void stroke(PixelBuffer buf, int width, int color) { stroke(buf, width, color, null, 0, 0); } - public void stroke(PixelBuffer buf, int width, int color, String dashArray, int dashOffset, float segLength) { - - if (dashArray == null) { - for(int i=0; i 0) { - float actualLength = 0; - for(int i=0; i