refactor TileClipper:

- move clipLine() to LineClipper
This commit is contained in:
Hannes Janetzek 2014-05-13 01:53:58 +02:00
parent f62ea65f25
commit dfe6ca99ce
3 changed files with 130 additions and 122 deletions

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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;
}
}