refactor TileClipper:
- move clipLine() to LineClipper
This commit is contained in:
parent
f62ea65f25
commit
dfe6ca99ce
@ -238,7 +238,7 @@ public class PathLayer extends Layer {
|
|||||||
|
|
||||||
public Worker(Map map) {
|
public Worker(Map map) {
|
||||||
super(map, 0, new Task(), new Task());
|
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];
|
mPPoints = new float[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,6 +339,8 @@ public class PathLayer extends Layer {
|
|||||||
float prevX = x;
|
float prevX = x;
|
||||||
float prevY = y;
|
float prevY = y;
|
||||||
|
|
||||||
|
float[] segment = null;
|
||||||
|
|
||||||
for (int j = 2; j < size * 2; j += 2) {
|
for (int j = 2; j < size * 2; j += 2) {
|
||||||
x = (int) ((mPreprojected[j + 0] - mx) * scale);
|
x = (int) ((mPreprojected[j + 0] - mx) * scale);
|
||||||
y = (int) ((mPreprojected[j + 1] - my) * scale);
|
y = (int) ((mPreprojected[j + 1] - my) * scale);
|
||||||
@ -368,10 +370,11 @@ public class PathLayer extends Layer {
|
|||||||
ll.addLine(projected, i, false);
|
ll.addLine(projected, i, false);
|
||||||
|
|
||||||
if (clip < 0) {
|
if (clip < 0) {
|
||||||
// add line segment
|
/* add line segment */
|
||||||
ll.addLine(mClipper.out, 4, false);
|
segment = mClipper.getLine(segment, 0);
|
||||||
prevX = mClipper.out[2];
|
ll.addLine(segment, 4, false);
|
||||||
prevY = mClipper.out[3];
|
prevX = mClipper.outX2;
|
||||||
|
prevY = mClipper.outY2;
|
||||||
}
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -16,6 +16,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.oscim.utils.geom;
|
package org.oscim.utils.geom;
|
||||||
|
|
||||||
|
import org.oscim.core.GeometryBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* from http://en.wikipedia.org/wiki/Cohen%E2%80%93
|
* from http://en.wikipedia.org/wiki/Cohen%E2%80%93
|
||||||
* Sutherland_algorithm
|
* Sutherland_algorithm
|
||||||
@ -29,34 +31,30 @@ public class LineClipper {
|
|||||||
public static final int BOTTOM = 4; // 0100
|
public static final int BOTTOM = 4; // 0100
|
||||||
public static final int TOP = 8; // 1000
|
public static final int TOP = 8; // 1000
|
||||||
|
|
||||||
private final int xmin, xmax, ymin, ymax;
|
private float xmin, xmax, ymin, ymax;
|
||||||
public final float[] out;
|
|
||||||
|
|
||||||
public LineClipper(int minx, int miny, int maxx, int maxy) {
|
public LineClipper(float minx, float miny, float maxx, float maxy) {
|
||||||
this.xmin = minx;
|
this.xmin = minx;
|
||||||
this.ymin = miny;
|
this.ymin = miny;
|
||||||
this.xmax = maxx;
|
this.xmax = maxx;
|
||||||
this.ymax = maxy;
|
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.xmin = minx;
|
||||||
this.ymin = miny;
|
this.ymin = miny;
|
||||||
this.xmax = maxx;
|
this.xmax = maxx;
|
||||||
this.ymax = maxy;
|
this.ymax = maxy;
|
||||||
if (keepResult)
|
|
||||||
this.out = new float[4];
|
|
||||||
else
|
|
||||||
this.out = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int mPrevOutcode;
|
private int mPrevOutcode;
|
||||||
private float mPrevX;
|
private float mPrevX;
|
||||||
private float mPrevY;
|
private float mPrevY;
|
||||||
|
|
||||||
//public int outX;
|
public float outX1;
|
||||||
//public int outY;
|
public float outY1;
|
||||||
|
public float outX2;
|
||||||
|
public float outY2;
|
||||||
|
|
||||||
public boolean clipStart(float x0, float y0) {
|
public boolean clipStart(float x0, float y0) {
|
||||||
mPrevX = x0;
|
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
|
* @return 0 if not intersection, 1 fully within, -1 clipped (and 'out' set
|
||||||
* to new points)
|
* to new points)
|
||||||
*/
|
*/
|
||||||
@ -101,8 +97,7 @@ public class LineClipper {
|
|||||||
// Bitwise AND is not 0. Trivially reject
|
// Bitwise AND is not 0. Trivially reject
|
||||||
accept = 0;
|
accept = 0;
|
||||||
} else {
|
} else {
|
||||||
accept = clip(mPrevX, mPrevY, x1, y1, xmin, ymin, xmax, ymax, mPrevOutcode, outcode,
|
accept = clip(mPrevX, mPrevY, x1, y1, mPrevOutcode, outcode) ? -1 : 0;
|
||||||
this.out) ? -1 : 0;
|
|
||||||
}
|
}
|
||||||
mPrevOutcode = outcode;
|
mPrevOutcode = outcode;
|
||||||
mPrevX = x1;
|
mPrevX = x1;
|
||||||
@ -111,45 +106,51 @@ public class LineClipper {
|
|||||||
return accept;
|
return accept;
|
||||||
}
|
}
|
||||||
|
|
||||||
// CohenSutherland clipping algorithm clips a line from
|
public int clipSegment(float x1, float y1, float x2, float y2) {
|
||||||
// P0 = (x0, y0) to P1 = (x1, y1) against a rectangle with
|
clipStart(x1, y1);
|
||||||
// diagonal from (xmin, ymin) to (xmax, ymax).
|
return clipNext(x2, y2);
|
||||||
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) {
|
|
||||||
|
|
||||||
|
/* 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;
|
boolean accept = false;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if ((outcode0 | outcode1) == 0) {
|
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;
|
accept = true;
|
||||||
break;
|
break;
|
||||||
} else if ((outcode0 & outcode1) != 0) {
|
} 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;
|
break;
|
||||||
} else {
|
} else {
|
||||||
// failed both tests, so calculate the line segment to clip
|
/* failed both tests, so calculate the line segment to clip
|
||||||
// from an outside point to an intersection with clip edge
|
* from an outside point to an intersection with clip edge */
|
||||||
float x = 0;
|
float x = 0;
|
||||||
float y = 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;
|
int outcodeOut = (outcode0 == 0) ? outcode1 : outcode0;
|
||||||
// Now find the intersection point;
|
/* Now find the intersection point;
|
||||||
// use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope) * (y - y0)
|
* use formulas y = y0 + slope * (x - x0), x = x0 + (1 / slope)
|
||||||
if ((outcodeOut & TOP) != 0) { // point is above the clip rectangle
|
* * (y - y0) */
|
||||||
|
if ((outcodeOut & TOP) != 0) {
|
||||||
|
/* point is above the clip rectangle */
|
||||||
x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
|
x = x0 + (x1 - x0) * (ymax - y0) / (y1 - y0);
|
||||||
y = ymax;
|
y = ymax;
|
||||||
} else if ((outcodeOut & BOTTOM) != 0) {
|
} 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);
|
x = x0 + (x1 - x0) * (ymin - y0) / (y1 - y0);
|
||||||
y = ymin;
|
y = ymin;
|
||||||
} else if ((outcodeOut & RIGHT) != 0) {
|
} 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);
|
y = y0 + (y1 - y0) * (xmax - x0) / (x1 - x0);
|
||||||
x = xmax;
|
x = xmax;
|
||||||
} else if ((outcodeOut & LEFT) != 0) {
|
} 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);
|
y = y0 + (y1 - y0) * (xmin - x0) / (x1 - x0);
|
||||||
x = xmin;
|
x = xmin;
|
||||||
}
|
}
|
||||||
@ -164,8 +165,8 @@ public class LineClipper {
|
|||||||
else if (y > ymax)
|
else if (y > ymax)
|
||||||
outcode |= TOP;
|
outcode |= TOP;
|
||||||
|
|
||||||
// Now we move outside point to intersection point to clip
|
/* Now we move outside point to intersection point to clip
|
||||||
// and get ready for next pass.
|
* and get ready for next pass. */
|
||||||
if (outcodeOut == outcode0) {
|
if (outcodeOut == outcode0) {
|
||||||
x0 = x;
|
x0 = x;
|
||||||
y0 = y;
|
y0 = y;
|
||||||
@ -177,12 +178,88 @@ public class LineClipper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (accept && out != null) {
|
if (accept) {
|
||||||
out[0] = x0;
|
outX1 = x0;
|
||||||
out[1] = y0;
|
outY1 = y0;
|
||||||
out[2] = x1;
|
outX2 = x1;
|
||||||
out[3] = y1;
|
outY2 = y1;
|
||||||
}
|
}
|
||||||
return accept;
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,12 +19,12 @@ package org.oscim.utils.geom;
|
|||||||
import org.oscim.core.GeometryBuffer;
|
import org.oscim.core.GeometryBuffer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clip polygon to a rectangle. Output cannot expected to be valid
|
* Clip polygons and lines to a rectangle. Output cannot expected to be valid
|
||||||
* Simple-Feature geometry, i.e. all rings are clipped independently
|
* Simple-Feature geometry, i.e. all polygon rings are clipped independently
|
||||||
* so that inner and outer rings might touch, etc.
|
* so that inner and outer rings might touch, etc.
|
||||||
*
|
*
|
||||||
* based on http://www.cs.rit.edu/~icss571/clipTrans/PolyClipBack.html
|
* based on http://www.cs.rit.edu/~icss571/clipTrans/PolyClipBack.html
|
||||||
* */
|
*/
|
||||||
public class TileClipper {
|
public class TileClipper {
|
||||||
private float minX;
|
private float minX;
|
||||||
private float maxX;
|
private float maxX;
|
||||||
@ -36,7 +36,7 @@ public class TileClipper {
|
|||||||
this.minY = minY;
|
this.minY = minY;
|
||||||
this.maxX = maxX;
|
this.maxX = maxX;
|
||||||
this.maxY = maxY;
|
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) {
|
public void setRect(float minX, float minY, float maxX, float maxY) {
|
||||||
@ -44,10 +44,10 @@ public class TileClipper {
|
|||||||
this.minY = minY;
|
this.minY = minY;
|
||||||
this.maxX = maxX;
|
this.maxX = maxX;
|
||||||
this.maxY = maxY;
|
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);
|
private final GeometryBuffer mGeomOut = new GeometryBuffer(10, 1);
|
||||||
|
|
||||||
@ -77,7 +77,7 @@ public class TileClipper {
|
|||||||
GeometryBuffer out = mGeomOut;
|
GeometryBuffer out = mGeomOut;
|
||||||
out.clear();
|
out.clear();
|
||||||
|
|
||||||
int numLines = clipLine(geom, out);
|
int numLines = mLineClipper.clipLine(geom, out);
|
||||||
|
|
||||||
short idx[] = geom.ensureIndexSize(numLines + 1, false);
|
short idx[] = geom.ensureIndexSize(numLines + 1, false);
|
||||||
System.arraycopy(out.index, 0, idx, 0, numLines);
|
System.arraycopy(out.index, 0, idx, 0, numLines);
|
||||||
@ -255,76 +255,4 @@ public class TileClipper {
|
|||||||
py = cy;
|
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user