diff --git a/vtm/src/org/oscim/layers/PathLayer.java b/vtm/src/org/oscim/layers/PathLayer.java index 3bdb11e6..ec367ab9 100644 --- a/vtm/src/org/oscim/layers/PathLayer.java +++ b/vtm/src/org/oscim/layers/PathLayer.java @@ -238,7 +238,7 @@ public class PathLayer extends Layer { public Worker(Map map) { super(map, 0, new Task(), new Task()); - mClipper = new LineClipper(-max, -max, max, max, true); + mClipper = new LineClipper(-max, -max, max, max); mPPoints = new float[0]; } @@ -339,6 +339,8 @@ public class PathLayer extends Layer { float prevX = x; float prevY = y; + float[] segment = null; + for (int j = 2; j < size * 2; j += 2) { x = (int) ((mPreprojected[j + 0] - mx) * scale); y = (int) ((mPreprojected[j + 1] - my) * scale); @@ -368,10 +370,11 @@ public class PathLayer extends Layer { ll.addLine(projected, i, false); if (clip < 0) { - // add line segment - ll.addLine(mClipper.out, 4, false); - prevX = mClipper.out[2]; - prevY = mClipper.out[3]; + /* add line segment */ + segment = mClipper.getLine(segment, 0); + ll.addLine(segment, 4, false); + prevX = mClipper.outX2; + prevY = mClipper.outY2; } i = 0; continue; diff --git a/vtm/src/org/oscim/utils/geom/LineClipper.java b/vtm/src/org/oscim/utils/geom/LineClipper.java index 8bf3ad57..18a31e62 100644 --- a/vtm/src/org/oscim/utils/geom/LineClipper.java +++ b/vtm/src/org/oscim/utils/geom/LineClipper.java @@ -16,6 +16,8 @@ */ package org.oscim.utils.geom; +import org.oscim.core.GeometryBuffer; + /** * from http://en.wikipedia.org/wiki/Cohen%E2%80%93 * Sutherland_algorithm @@ -29,34 +31,30 @@ public class LineClipper { public static final int BOTTOM = 4; // 0100 public static final int TOP = 8; // 1000 - private final int xmin, xmax, ymin, ymax; - public final float[] out; + private float xmin, xmax, ymin, ymax; - public LineClipper(int minx, int miny, int maxx, int maxy) { + public LineClipper(float minx, float miny, float maxx, float maxy) { this.xmin = minx; this.ymin = miny; this.xmax = maxx; this.ymax = maxy; - this.out = null; } - public LineClipper(int minx, int miny, int maxx, int maxy, boolean keepResult) { + public void setRect(float minx, float miny, float maxx, float maxy) { this.xmin = minx; this.ymin = miny; this.xmax = maxx; this.ymax = maxy; - if (keepResult) - this.out = new float[4]; - else - this.out = null; } private int mPrevOutcode; private float mPrevX; private float mPrevY; - //public int outX; - //public int outY; + public float outX1; + public float outY1; + public float outX2; + public float outY2; public boolean clipStart(float x0, float y0) { mPrevX = x0; @@ -76,8 +74,6 @@ public class LineClipper { } /** - * @param x1 ... - * @param y1 ... * @return 0 if not intersection, 1 fully within, -1 clipped (and 'out' set * to new points) */ @@ -101,8 +97,7 @@ public class LineClipper { // Bitwise AND is not 0. Trivially reject accept = 0; } else { - accept = clip(mPrevX, mPrevY, x1, y1, xmin, ymin, xmax, ymax, mPrevOutcode, outcode, - this.out) ? -1 : 0; + accept = clip(mPrevX, mPrevY, x1, y1, mPrevOutcode, outcode) ? -1 : 0; } mPrevOutcode = outcode; mPrevX = x1; @@ -111,45 +106,51 @@ public class LineClipper { return accept; } - // CohenSutherland clipping algorithm clips a line from - // P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with - // diagonal from (xmin, ymin) to (xmax, ymax). - private static boolean clip(float x0, float y0, float x1, float y1, - int xmin, int ymin, int xmax, int ymax, int outcode0, int outcode1, float[] out) { + public int clipSegment(float x1, float y1, float x2, float y2) { + clipStart(x1, y1); + return clipNext(x2, y2); + } + /* CohenSutherland clipping algorithm clips a line from + * P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with + * diagonal from (xmin, ymin) to (xmax, ymax). + * based on en.wikipedia.org/wiki/Cohen-Sutherland */ + private boolean clip(float x0, float y0, float x1, float y1, int outcode0, int outcode1) { boolean accept = false; while (true) { if ((outcode0 | outcode1) == 0) { - // Bitwise OR is 0. Trivially accept and get out of loop + /* Bitwise OR is 0. Trivially accept and get out of loop */ accept = true; break; } else if ((outcode0 & outcode1) != 0) { - // Bitwise AND is not 0. Trivially reject and get out of loop + /* Bitwise AND is not 0. Trivially reject and get out of loop */ break; } else { - // failed both tests, so calculate the line segment to clip - // from an outside point to an intersection with clip edge + /* failed both tests, so calculate the line segment to clip + * from an outside point to an intersection with clip edge */ float x = 0; float y = 0; - // At least one endpoint is outside the clip rectangle; pick it. + /* At least one endpoint is outside the clip rectangle; pick it. */ int outcodeOut = (outcode0 == 0) ? outcode1 : outcode0; - // Now find the intersection point; - // use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0) - if ((outcodeOut & TOP) != 0) { // point is above the clip rectangle + /* Now find the intersection point; + * use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) + * * (y - y0) */ + if ((outcodeOut & TOP) != 0) { + /* point is above the clip rectangle */ x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0); y = ymax; } else if ((outcodeOut & BOTTOM) != 0) { - // point is below the clip rectangle + /* point is below the clip rectangle */ x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0); y = ymin; } else if ((outcodeOut & RIGHT) != 0) { - // point is to the right of clip rectangle + /* point is to the right of clip rectangle */ y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0); x = xmax; } else if ((outcodeOut & LEFT) != 0) { - // point is to the left of clip rectangle + /* point is to the left of clip rectangle */ y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0); x = xmin; } @@ -164,8 +165,8 @@ public class LineClipper { else if (y > ymax) outcode |= TOP; - // Now we move outside point to intersection point to clip - // and get ready for next pass. + /* Now we move outside point to intersection point to clip + * and get ready for next pass. */ if (outcodeOut == outcode0) { x0 = x; y0 = y; @@ -177,12 +178,88 @@ public class LineClipper { } } } - if (accept && out != null) { - out[0] = x0; - out[1] = y0; - out[2] = x1; - out[3] = y1; + if (accept) { + outX1 = x0; + outY1 = y0; + outX2 = x1; + outY2 = y1; } return accept; } + + public float[] getLine(float out[], int offset) { + if (out == null) + return new float[] { outX1, outY1, outX2, outY2 }; + + out[offset + 0] = outX1; + out[offset + 1] = outY1; + out[offset + 2] = outX2; + out[offset + 3] = outY2; + return out; + } + + public int clipLine(GeometryBuffer in, GeometryBuffer out) { + int pointPos = 0; + int numLines = 0; + for (int i = 0, n = in.index.length; i < n; i++) { + int len = in.index[i]; + if (len < 0) + break; + + if (len < 4) { + pointPos += len; + continue; + } + + if (len == 0) { + continue; + } + + int inPos = pointPos; + int end = inPos + len; + + float prevX = in.points[inPos + 0]; + float prevY = in.points[inPos + 1]; + + boolean inside = clipStart(prevX, prevY); + + if (inside) { + out.startLine(); + out.addPoint(prevX, prevY); + numLines++; + } + + for (inPos += 2; inPos < end; inPos += 2) { + /* get the current way point coordinates */ + float curX = in.points[inPos]; + float curY = in.points[inPos + 1]; + + int clip; + if ((clip = clipNext(curX, curY)) != 0) { + if (clip < 0) { + if (inside) { + /* previous was inside */ + out.addPoint(outX2, outY2); + inside = false; + + } else { + /* previous was outside */ + out.startLine(); + numLines++; + out.addPoint(outX1, outY1); + out.addPoint(outX2, outY2); + + inside = clipStart(curX, curY); + } + } else { + out.addPoint(curX, curY); + } + } else { + inside = false; + } + } + pointPos += len; + } + return numLines; + } } diff --git a/vtm/src/org/oscim/utils/geom/TileClipper.java b/vtm/src/org/oscim/utils/geom/TileClipper.java index 95583de8..0a104a32 100644 --- a/vtm/src/org/oscim/utils/geom/TileClipper.java +++ b/vtm/src/org/oscim/utils/geom/TileClipper.java @@ -19,12 +19,12 @@ package org.oscim.utils.geom; import org.oscim.core.GeometryBuffer; /** - * Clip polygon to a rectangle. Output cannot expected to be valid - * Simple-Feature geometry, i.e. all rings are clipped independently + * Clip polygons and lines to a rectangle. Output cannot expected to be valid + * Simple-Feature geometry, i.e. all polygon rings are clipped independently * so that inner and outer rings might touch, etc. * * based on http://www.cs.rit.edu/~icss571/clipTrans/PolyClipBack.html - * */ + */ public class TileClipper { private float minX; private float maxX; @@ -36,7 +36,7 @@ public class TileClipper { this.minY = minY; this.maxX = maxX; this.maxY = maxY; - mLineClipper = new LineClipper((int) minX, (int) minY, (int) maxX, (int) maxY, true); + mLineClipper = new LineClipper(minX, minY, maxX, maxY); } public void setRect(float minX, float minY, float maxX, float maxY) { @@ -44,10 +44,10 @@ public class TileClipper { this.minY = minY; this.maxX = maxX; this.maxY = maxY; - mLineClipper = new LineClipper((int) minX, (int) minY, (int) maxX, (int) maxY, true); + mLineClipper.setRect(minX, minY, maxX, maxY); } - private LineClipper mLineClipper; + private final LineClipper mLineClipper; private final GeometryBuffer mGeomOut = new GeometryBuffer(10, 1); @@ -77,7 +77,7 @@ public class TileClipper { GeometryBuffer out = mGeomOut; out.clear(); - int numLines = clipLine(geom, out); + int numLines = mLineClipper.clipLine(geom, out); short idx[] = geom.ensureIndexSize(numLines + 1, false); System.arraycopy(out.index, 0, idx, 0, numLines); @@ -255,76 +255,4 @@ public class TileClipper { py = cy; } } - - private int clipLine(GeometryBuffer in, GeometryBuffer out) { - - int pointPos = 0; - int numLines = 0; - for (int i = 0, n = in.index.length; i < n; i++) { - int len = in.index[i]; - if (len < 0) - break; - - if (len < 4) { - pointPos += len; - continue; - } - - if (len == 0) { - continue; - } - - int inPos = pointPos; - int end = inPos + len; - - float prevX = in.points[inPos + 0]; - float prevY = in.points[inPos + 1]; - - boolean inside = mLineClipper.clipStart(prevX, prevY); - - if (inside) { - out.startLine(); - out.addPoint(prevX, prevY); - numLines++; - } - - for (inPos += 2; inPos < end; inPos += 2) { - // get the current way point coordinates - float curX = in.points[inPos]; - float curY = in.points[inPos + 1]; - - int clip; - if ((clip = mLineClipper.clipNext(curX, curY)) != 0) { - //System.out.println(inside + " clip: " + clip + " " - // + Arrays.toString(mLineClipper.out)); - if (clip < 0) { - if (inside) { - // previous was inside - out.addPoint(mLineClipper.out[2], mLineClipper.out[3]); - inside = false; - - } else { - // previous was outside - out.startLine(); - numLines++; - out.addPoint(mLineClipper.out[0], mLineClipper.out[1]); - out.addPoint(mLineClipper.out[2], mLineClipper.out[3]); - - inside = mLineClipper.clipStart(curX, curY); - } - } else { - out.addPoint(curX, curY); - - } - } else { - inside = false; - } - - } - - pointPos += len; - } - - return numLines; - } }