GeometryUtils: fix clockwise calculation (#704)

This commit is contained in:
Gustl22 2019-03-19 18:47:05 +01:00 committed by Emux
parent 1051aacc7c
commit 271cab1212
No known key found for this signature in database
GPG Key ID: 64ED9980896038C3
5 changed files with 26 additions and 17 deletions

View File

@ -8,9 +8,10 @@ public class GeometryTest {
@Test @Test
public void testIsTrisClockwise() { public void testIsTrisClockwise() {
// Coordinate system is LHS
float[] pA = new float[]{0, 0}; float[] pA = new float[]{0, 0};
float[] pB = new float[]{1, 1}; float[] pB = new float[]{1, 0};
float[] pC = new float[]{1, 0}; float[] pC = new float[]{1, 1};
float area = GeometryUtils.isTrisClockwise(pA, pB, pC); float area = GeometryUtils.isTrisClockwise(pA, pB, pC);
Assert.assertTrue(area > 0); Assert.assertTrue(area > 0);
@ -21,12 +22,13 @@ public class GeometryTest {
@Test @Test
public void testIsClockwise() { public void testIsClockwise() {
float[] points = new float[]{0, 0, 1, 1, 1, 0}; // Coordinate system is LHS
float[] points = new float[]{0, 0, 1, 0, 1, 1};
float area = GeometryUtils.isClockwise(points, points.length); float area = GeometryUtils.isClockwise(points, points.length);
Assert.assertTrue(area > 0); Assert.assertTrue(area > 0);
points = new float[]{0, 0, 1, 0, 1, 1}; points = new float[]{0, 0, 1, 1, 1, 0};
area = GeometryUtils.isClockwise(points, points.length); area = GeometryUtils.isClockwise(points, points.length);
Assert.assertTrue(area < 0); Assert.assertTrue(area < 0);
} }

View File

@ -479,12 +479,16 @@ public class GeometryBuffer {
* Calculates geometry area, only polygon outer ring is taken into account. * Calculates geometry area, only polygon outer ring is taken into account.
* *
* @return unsigned polygon area, 0 for other geometries * @return unsigned polygon area, 0 for other geometries
* @see GeometryUtils#area(float[], int)
*/ */
public float area() { public float area() {
float area = isClockwise(); float area = isClockwise();
return area < 0 ? -area : area; return area < 0 ? -area : area;
} }
/**
* @see GeometryUtils#isClockwise(float[], int).
*/
public float isClockwise() { public float isClockwise() {
if (isPoint() || isLine() || getNumPoints() < 3) if (isPoint() || isLine() || getNumPoints() < 3)
return 0f; return 0f;

View File

@ -155,7 +155,7 @@ public class BuildingLayer extends Layer implements TileLoaderThemeHook, ZoomLim
mBuildings.put(tile.hashCode(), buildingElements); mBuildings.put(tile.hashCode(), buildingElements);
} }
element = new MapElement(element); // Deep copy, because element will be cleared element = new MapElement(element); // Deep copy, because element will be cleared
if (RAW_DATA && element.isClockwise() > 0) { if (RAW_DATA && element.isClockwise() < 0) {
// Buildings must be counter clockwise in VTM (mirrored to OSM) // Buildings must be counter clockwise in VTM (mirrored to OSM)
element.reverse(); element.reverse();
} }

View File

@ -700,7 +700,7 @@ public final class S3DBUtils {
if (Arrays.equals(ridgePoints.get(k), ridgePoints.get(secIndex))) if (Arrays.equals(ridgePoints.get(k), ridgePoints.get(secIndex)))
ridgeSkipFaceIndex.add(k); ridgeSkipFaceIndex.add(k);
} }
if (isClockwise < 0 && IMPROVE_RIDGE_CALCULATION) { if (isClockwise > 0 && IMPROVE_RIDGE_CALCULATION) {
// TODO Improve handling of counter clockwise faces and support multiple faces // TODO Improve handling of counter clockwise faces and support multiple faces
isTessellateAble = false; isTessellateAble = false;
break; break;
@ -845,7 +845,7 @@ public final class S3DBUtils {
} }
} }
// Scale of normal vec // Scale of normal vec
maxDist = -Math.signum(GeometryUtils.isTrisClockwise( maxDist = Math.signum(GeometryUtils.isTrisClockwise(
pL, pL,
GeometryUtils.sumVec(pL, vL), GeometryUtils.sumVec(pL, vL),
splitLinePoint)) * (maxDist / 2); splitLinePoint)) * (maxDist / 2);
@ -861,7 +861,7 @@ public final class S3DBUtils {
List<float[]> elementPoints2 = new ArrayList<>(); List<float[]> elementPoints2 = new ArrayList<>();
float[] secSplitPoint = GeometryUtils.sumVec(splitLinePoint, vL); float[] secSplitPoint = GeometryUtils.sumVec(splitLinePoint, vL);
float sideLastPoint = Math.signum(GeometryUtils.isTrisClockwise(splitLinePoint, secSplitPoint, point3Fs.get(groundSize - 1))); float sideLastPoint = Math.signum(GeometryUtils.isTrisClockwise(splitLinePoint, secSplitPoint, point3Fs.get(groundSize - 1)));
degreeNormL = sideLastPoint < 0 ? degreeNormL : (degreeNormL + 180f) % 360; // Correct angle degreeNormL = sideLastPoint > 0 ? degreeNormL : (degreeNormL + 180f) % 360; // Correct angle
List<Integer> intersection1 = new ArrayList<>(), intersection2 = new ArrayList<>(); List<Integer> intersection1 = new ArrayList<>(), intersection2 = new ArrayList<>();
for (int k = 0; k < groundSize; k++) { for (int k = 0; k < groundSize; k++) {
// If point is not on the same side as the previous point, the split line intersect and can calc split point // If point is not on the same side as the previous point, the split line intersect and can calc split point

View File

@ -69,10 +69,11 @@ public final class GeometryUtils {
/** /**
* Returns the unsigned area of polygon. * Returns the unsigned area of polygon.
* *
* @param n number of points * @param size the number of point coordinates
* @return unsigned polygon area
*/ */
public static float area(float[] points, int n) { public static float area(float[] points, int size) {
float area = isClockwise(points, n); float area = isClockwise(points, size);
return area < 0 ? -area : area; return area < 0 ? -area : area;
} }
@ -311,33 +312,35 @@ public final class GeometryUtils {
/** /**
* Is polygon clockwise. * Is polygon clockwise.
* Note that the coordinate system is left hand side.
* *
* @param points the points array * @param points the points array
* @param n the number of points * @param size the number of point coordinates
* @return the signed area of the polygon * @return the signed area of the polygon
* positive: clockwise * positive: clockwise
* negative: counter-clockwise * negative: counter-clockwise
* 0: collinear * 0: collinear
*/ */
public static float isClockwise(float[] points, int n) { public static float isClockwise(float[] points, int size) {
float area = 0f; float area = 0f;
for (int i = 0; i < n - 2; i += 2) { for (int i = 0; i < size - 2; i += 2) {
area += (points[i + 1] * points[i + 2]) - (points[i] * points[i + 3]); area += (points[i] * points[i + 3]) - (points[i + 1] * points[i + 2]);
} }
area += (points[n - 1] * points[0]) - (points[n - 2] * points[1]); area += (points[size - 2] * points[1]) - (points[size - 1] * points[0]);
return 0.5f * area; return 0.5f * area;
} }
/** /**
* Indicates the turn of tris pA-pB-pC. * Indicates the turn of tris pA-pB-pC.
* Note that the coordinate system is left hand side.
* *
* @return positive: clockwise * @return positive: clockwise
* negative: counter-clockwise * negative: counter-clockwise
* 0: collinear * 0: collinear
*/ */
public static float isTrisClockwise(float[] pA, float[] pB, float[] pC) { public static float isTrisClockwise(float[] pA, float[] pB, float[] pC) {
return (pB[1] - pA[1]) * (pC[0] - pA[0]) - (pB[0] - pA[0]) * (pC[1] - pA[1]); return (pB[0] - pA[0]) * (pC[1] - pA[1]) - (pB[1] - pA[1]) * (pC[0] - pA[0]);
} }
/** /**