174 lines
3.7 KiB
Java
174 lines
3.7 KiB
Java
/*
|
|
* Copyright 2012 Hannes Janetzek
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify it under the
|
|
* terms of the GNU Lesser General License as published by the Free Software
|
|
* Foundation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
|
* PARTICULAR PURPOSE. See the GNU Lesser General License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General License along with
|
|
* this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
package org.oscim.renderer;
|
|
|
|
|
|
public abstract class ScanBox {
|
|
/*
|
|
* ported from Polymaps: Layer.js
|
|
*/
|
|
|
|
static class Edge {
|
|
float x0, y0, x1, y1, dx, dy;
|
|
|
|
void set(float x0, float y0, float x1, float y1) {
|
|
if (y0 <= y1) {
|
|
this.x0 = x0;
|
|
this.y0 = y0;
|
|
this.x1 = x1;
|
|
this.y1 = y1;
|
|
} else {
|
|
this.x0 = x1;
|
|
this.y0 = y1;
|
|
this.x1 = x0;
|
|
this.y1 = y0;
|
|
}
|
|
this.dx = this.x1 - this.x0;
|
|
this.dy = this.y1 - this.y0;
|
|
}
|
|
}
|
|
|
|
private Edge ab = new Edge();
|
|
private Edge bc = new Edge();
|
|
private Edge ca = new Edge();
|
|
private float minX, maxX;
|
|
|
|
protected int mZoom;
|
|
|
|
abstract void setVisible(int y, int x1, int x2);
|
|
|
|
public void scan(float[] coords, int zoom) {
|
|
mZoom = zoom;
|
|
|
|
maxX = Float.MIN_VALUE;
|
|
minX = Float.MAX_VALUE;
|
|
|
|
for(int i = 0; i < 8; i += 2){
|
|
float x = coords[i];
|
|
if (x > maxX)
|
|
maxX = x;
|
|
if (x < minX)
|
|
minX = x;
|
|
}
|
|
maxX = (float)Math.ceil(maxX);
|
|
minX = (float)Math.floor(minX);
|
|
|
|
// top-left -> top-right
|
|
ab.set(coords[0], coords[1], coords[2], coords[3]);
|
|
// top-right -> bottom-right
|
|
bc.set(coords[2], coords[3], coords[4], coords[5]);
|
|
// bottom-right -> bottom-left
|
|
ca.set(coords[4], coords[5], coords[0], coords[1]);
|
|
|
|
scanTriangle();
|
|
|
|
// top-left -> bottom-right
|
|
ab.set(coords[0], coords[1], coords[4], coords[5]);
|
|
// bottom-right -> bottom-left
|
|
bc.set(coords[4], coords[5], coords[6], coords[7]);
|
|
// bottom-left -> top-left
|
|
ca.set(coords[6], coords[7], coords[0], coords[1]);
|
|
|
|
scanTriangle();
|
|
}
|
|
|
|
private void scanTriangle() {
|
|
|
|
// sort so that ca.dy > bc.dy > ab.dy
|
|
if (ab.dy > bc.dy) {
|
|
Edge t = ab;
|
|
ab = bc;
|
|
bc = t;
|
|
}
|
|
if (ab.dy > ca.dy) {
|
|
Edge t = ab;
|
|
ab = ca;
|
|
ca = t;
|
|
}
|
|
if (bc.dy > ca.dy) {
|
|
Edge t = bc;
|
|
bc = ca;
|
|
ca = t;
|
|
}
|
|
|
|
// shouldnt be possible, anyway
|
|
if (ca.dy == 0)
|
|
return;
|
|
|
|
if (ab.dy > 0.1)
|
|
scanSpans(ca, ab);
|
|
|
|
if (bc.dy > 0.1)
|
|
scanSpans(ca, bc);
|
|
}
|
|
|
|
private void scanSpans(Edge e0, Edge e1) {
|
|
|
|
// scan the y-range of the edge with less dy
|
|
int y0 = (int) Math.max(0, Math.floor(e1.y0));
|
|
int y1 = (int) Math.min((1 << mZoom), Math.ceil(e1.y1));
|
|
|
|
// sort edge by x-coordinate
|
|
if (e0.x0 == e1.x0 && e0.y0 == e1.y0) {
|
|
// bottom-flat
|
|
if (e0.x0 + e1.dy / e0.dy * e0.dx < e1.x1) {
|
|
Edge t = e0;
|
|
e0 = e1;
|
|
e1 = t;
|
|
}
|
|
} else {
|
|
// top-flat
|
|
if (e0.x1 - e1.dy / e0.dy * e0.dx < e1.x0) {
|
|
Edge t = e0;
|
|
e0 = e1;
|
|
e1 = t;
|
|
}
|
|
}
|
|
|
|
float m0 = e0.dx / e0.dy;
|
|
float m1 = e1.dx / e1.dy;
|
|
|
|
// e0 goes to the right, e1 to the left
|
|
int d0 = e0.dx > 0 ? 1 : 0; // use y + 1 to compute x0
|
|
int d1 = e1.dx < 0 ? 1 : 0; // use y + 1 to compute x1
|
|
float dy;
|
|
|
|
for (int y = y0; y < y1; y++) {
|
|
|
|
dy = d0 + y - e0.y0;
|
|
if (dy > e0.dy)
|
|
dy = e0.dy;
|
|
|
|
float x0 = (float)Math.ceil(e0.x0 + m0 * dy);
|
|
|
|
dy = d1 + y - e1.y0;
|
|
if (dy > e1.dy)
|
|
dy = e1.dy;
|
|
|
|
float x1 = (float)Math.floor(e1.x0 + m1 * dy);
|
|
|
|
if (x1 < minX)
|
|
x1 = minX;
|
|
|
|
if (x0 > maxX)
|
|
x0 = maxX;
|
|
|
|
if (x1 < x0)
|
|
setVisible(y, (int) x1, (int) x0);
|
|
}
|
|
}
|
|
}
|