diff --git a/vtm/src/org/oscim/core/GeometryBuffer.java b/vtm/src/org/oscim/core/GeometryBuffer.java index 5f18b7be..3e1ebf1f 100644 --- a/vtm/src/org/oscim/core/GeometryBuffer.java +++ b/vtm/src/org/oscim/core/GeometryBuffer.java @@ -1,7 +1,7 @@ /* * Copyright 2013 Hannes Janetzek * Copyright 2016 Andrey Novikov - * Copyright 2017 Gustl22 + * Copyright 2017-2019 Gustl22 * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -18,6 +18,9 @@ */ package org.oscim.core; +import org.oscim.utils.ArrayUtils; +import org.oscim.utils.geom.GeometryUtils; + import java.util.Arrays; /* TODO @@ -450,22 +453,34 @@ public class GeometryBuffer { /** * Calculates geometry area, only polygon outer ring is taken into account. * - * @return polygon area, 0 for other geometries + * @return unsigned polygon area, 0 for other geometries */ public float area() { + float area = isClockwise(); + return area < 0 ? -area : area; + } + + public float isClockwise() { if (isPoint() || isLine() || getNumPoints() < 3) return 0f; - float area = 0f; // use only outer ring - int n = index[0]; + return GeometryUtils.isClockwise(points, index[0]); + } - for (int i = 0; i < n - 2; i += 2) { - area = area + (points[i] * points[i + 3]) - (points[i + 1] * points[i + 2]); + /** + * Reverse the order of points for lines and polygons. + */ + public void reverse() { + if (isLine() || isPoly()) { + int count = 0; + for (int num : index) { + if (num < 0) + break; + ArrayUtils.reverse(points, count, count + num, 2); + count += num; + } } - area = area + (points[n - 2] * points[1]) - (points[n - 1] * points[0]); - - return 0.5f * area; } public String toString() { diff --git a/vtm/src/org/oscim/layers/tile/buildings/S3DBUtils.java b/vtm/src/org/oscim/layers/tile/buildings/S3DBUtils.java index 5d5ef2bf..fc3042d3 100644 --- a/vtm/src/org/oscim/layers/tile/buildings/S3DBUtils.java +++ b/vtm/src/org/oscim/layers/tile/buildings/S3DBUtils.java @@ -317,6 +317,8 @@ public final class S3DBUtils { public static boolean calcPyramidalMesh(GeometryBuffer element, float minHeight, float maxHeight) { float[] points = element.points; int[] index = element.index; + float[] topPoint = new float[3]; + topPoint[2] = maxHeight; for (int i = 0, pointPos = 0; i < index.length; i++) { if (index[i] < 0) { @@ -327,27 +329,13 @@ public final class S3DBUtils { int numPoints = index[i] / 2; if (numPoints < 0) continue; - float centerX = 0; - float centerY = 0; + // Init top of roof (attention with pointPos) + GeometryUtils.center(points, pointPos, numPoints << 1, topPoint); List point3Fs = new ArrayList<>(); - - // Calculate center and load points - for (int j = 0; j < (numPoints * 2); j += 2, pointPos += 2) { - float x = points[pointPos]; - float y = points[pointPos + 1]; - - point3Fs.add(new float[]{x, y, minHeight}); - - centerX += x; - centerY += y; - } - - centerX = centerX / numPoints; - centerY = centerY / numPoints; - - // Init top of roof - float[] topPoint = new float[]{centerX, centerY, maxHeight}; + // Load points + for (int j = 0; j < (numPoints * 2); j += 2, pointPos += 2) + point3Fs.add(new float[]{points[pointPos], points[pointPos + 1], minHeight}); // Write index: index gives the first point of triangle mesh (divided 3) int[] meshIndex = new int[numPoints * 3]; @@ -717,7 +705,7 @@ public final class S3DBUtils { if (Arrays.equals(ridgePoints.get(k), ridgePoints.get(secIndex))) 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 isTessellateAble = false; break; @@ -862,7 +850,7 @@ public final class S3DBUtils { } } // Scale of normal vec - maxDist = Math.signum(GeometryUtils.isTrisClockwise( + maxDist = -Math.signum(GeometryUtils.isTrisClockwise( pL, GeometryUtils.sumVec(pL, vL), splitLinePoint)) * (maxDist / 2); @@ -878,7 +866,7 @@ public final class S3DBUtils { List elementPoints2 = new ArrayList<>(); float[] secSplitPoint = GeometryUtils.sumVec(splitLinePoint, vL); 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 intersection1 = new ArrayList<>(), intersection2 = new ArrayList<>(); 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 diff --git a/vtm/src/org/oscim/tiling/source/LwHttp.java b/vtm/src/org/oscim/tiling/source/LwHttp.java index 070088bf..ff68bc28 100644 --- a/vtm/src/org/oscim/tiling/source/LwHttp.java +++ b/vtm/src/org/oscim/tiling/source/LwHttp.java @@ -457,7 +457,7 @@ public class LwHttp implements HttpEngine { for (int n = val; n > 0; n = n / 10, i++) buf[pos + i] = (byte) ('0' + n % 10); - ArrayUtils.reverse(buf, pos, pos + i); + ArrayUtils.reverse(buf, pos, pos + i, 1); return pos + i; } diff --git a/vtm/src/org/oscim/utils/ArrayUtils.java b/vtm/src/org/oscim/utils/ArrayUtils.java index 771d44d8..fa5ff7c8 100644 --- a/vtm/src/org/oscim/utils/ArrayUtils.java +++ b/vtm/src/org/oscim/utils/ArrayUtils.java @@ -1,5 +1,6 @@ /* * Copyright 2013 Hannes Janetzek + * Copyright 2019 Gustl22 * * This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * @@ -35,6 +36,32 @@ public class ArrayUtils { } } + /** + * Reverse an array. + * + * @param data the base array to be reversed + * @param left the left index to be reversed + * @param right the right index (excluded) + * @param stride the stride + */ + public static void reverse(T[] data, int left, int right, int stride) { + right -= stride; + + while (left < right) { + for (int i = 0; i < stride; i++) { + T tmp = data[left + i]; + data[left + i] = data[right + i]; + data[right + i] = tmp; + } + left += stride; + right -= stride; + } + } + + /** + * Reverse the array for primitive short. + * see {@link #reverse(Object[], int, int, int)} + */ public static void reverse(short[] data, int left, int right, int stride) { right -= stride; @@ -49,16 +76,39 @@ public class ArrayUtils { } } - public static void reverse(byte[] data, int left, int right) { - right -= 1; + /** + * Reverse the array for primitive float. + * see {@link #reverse(Object[], int, int, int)} + */ + public static void reverse(float[] data, int left, int right, int stride) { + right -= stride; while (left < right) { - byte tmp = data[left]; - data[left] = data[right]; - data[right] = tmp; + for (int i = 0; i < stride; i++) { + float tmp = data[left + i]; + data[left + i] = data[right + i]; + data[right + i] = tmp; + } + left += stride; + right -= stride; + } + } - left++; - right--; + /** + * Reverse the array for primitive byte. + * see {@link #reverse(Object[], int, int, int)} + */ + public static void reverse(byte[] data, int left, int right, int stride) { + right -= stride; + + while (left < right) { + for (int i = 0; i < stride; i++) { + byte tmp = data[left + i]; + data[left + i] = data[right + i]; + data[right + i] = tmp; + } + left += stride; + right -= stride; } } diff --git a/vtm/src/org/oscim/utils/geom/GeometryUtils.java b/vtm/src/org/oscim/utils/geom/GeometryUtils.java index 0eeb7d37..ec4e5006 100644 --- a/vtm/src/org/oscim/utils/geom/GeometryUtils.java +++ b/vtm/src/org/oscim/utils/geom/GeometryUtils.java @@ -66,6 +66,16 @@ public final class GeometryUtils { return inside; } + /** + * Returns the unsigned area of polygon. + * + * @param n number of points + */ + public static float area(float[] points, int n) { + float area = isClockwise(points, n); + return area < 0 ? -area : area; + } + public static float area(float ax, float ay, float bx, float by, float cx, float cy) { float area = ((ax - cx) * (by - cy) @@ -107,6 +117,33 @@ public final class GeometryUtils { return bisection; } + /** + * Calculates the center of a set of points. + * + * @param points the points array + * @param pointPos the start position of points + * @param n the number of points + * @param out the center output + * @return the center of points + */ + public static float[] center(float[] points, int pointPos, int n, float[] out) { + if (out == null) + out = new float[2]; + + // Calculate center + for (int i = 0; i < n; i += 2, pointPos += 2) { + float x = points[pointPos]; + float y = points[pointPos + 1]; + + out[0] += x; + out[1] += y; + } + out[0] = out[0] * 2 / n; + out[1] = out[1] * 2 / n; + + return out; + } + /** * @param a first vector * @param b second vector @@ -273,11 +310,34 @@ public final class GeometryUtils { } /** - * @return a positive value, if pA-pB-pC makes a counter-clockwise turn, - * negative for clockwise turn, and zero if the points are collinear. + * Is polygon clockwise. + * + * @param points the points array + * @param n the number of points + * @return the signed area of the polygon + * positive: clockwise + * negative: counter-clockwise + * 0: collinear + */ + public static float isClockwise(float[] points, int n) { + float area = 0f; + for (int i = 0; i < n - 2; i += 2) { + area += (points[i] * points[i + 3]) - (points[i + 1] * points[i + 2]); + } + area += (points[n - 2] * points[1]) - (points[n - 1] * points[0]); + + return 0.5f * area; + } + + /** + * Indicates the turn of tris pA-pB-pC. + * + * @return positive: clockwise + * negative: counter-clockwise + * 0: collinear */ public static float isTrisClockwise(float[] pA, float[] pB, float[] pC) { - return (pB[0] - pA[0]) * (pC[1] - pA[1]) - (pB[1] - pA[1]) * (pC[0] - pA[0]); + return (pB[1] - pA[1]) * (pC[0] - pA[0]) - (pB[0] - pA[0]) * (pC[1] - pA[1]); } /**