Extend GeometryUtils, ArrayUtils (#662)

This commit is contained in:
Gustl22 2019-02-18 14:06:47 +01:00 committed by Emux
parent 777d33a4de
commit 1f0b5509ed
No known key found for this signature in database
GPG Key ID: 64ED9980896038C3
5 changed files with 155 additions and 42 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2016 Andrey Novikov * Copyright 2016 Andrey Novikov
* Copyright 2017 Gustl22 * Copyright 2017-2019 Gustl22
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * This file is part of the OpenScienceMap project (http://www.opensciencemap.org).
* *
@ -18,6 +18,9 @@
*/ */
package org.oscim.core; package org.oscim.core;
import org.oscim.utils.ArrayUtils;
import org.oscim.utils.geom.GeometryUtils;
import java.util.Arrays; import java.util.Arrays;
/* TODO /* TODO
@ -450,22 +453,34 @@ 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 polygon area, 0 for other geometries * @return unsigned polygon area, 0 for other geometries
*/ */
public float area() { public float area() {
float area = isClockwise();
return area < 0 ? -area : area;
}
public float isClockwise() {
if (isPoint() || isLine() || getNumPoints() < 3) if (isPoint() || isLine() || getNumPoints() < 3)
return 0f; return 0f;
float area = 0f;
// use only outer ring // 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() { public String toString() {

View File

@ -317,6 +317,8 @@ public final class S3DBUtils {
public static boolean calcPyramidalMesh(GeometryBuffer element, float minHeight, float maxHeight) { public static boolean calcPyramidalMesh(GeometryBuffer element, float minHeight, float maxHeight) {
float[] points = element.points; float[] points = element.points;
int[] index = element.index; int[] index = element.index;
float[] topPoint = new float[3];
topPoint[2] = maxHeight;
for (int i = 0, pointPos = 0; i < index.length; i++) { for (int i = 0, pointPos = 0; i < index.length; i++) {
if (index[i] < 0) { if (index[i] < 0) {
@ -327,27 +329,13 @@ public final class S3DBUtils {
int numPoints = index[i] / 2; int numPoints = index[i] / 2;
if (numPoints < 0) continue; if (numPoints < 0) continue;
float centerX = 0; // Init top of roof (attention with pointPos)
float centerY = 0; GeometryUtils.center(points, pointPos, numPoints << 1, topPoint);
List<float[]> point3Fs = new ArrayList<>(); List<float[]> point3Fs = new ArrayList<>();
// Load points
// Calculate center and load points for (int j = 0; j < (numPoints * 2); j += 2, pointPos += 2)
for (int j = 0; j < (numPoints * 2); j += 2, pointPos += 2) { point3Fs.add(new float[]{points[pointPos], points[pointPos + 1], minHeight});
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};
// Write index: index gives the first point of triangle mesh (divided 3) // Write index: index gives the first point of triangle mesh (divided 3)
int[] meshIndex = new int[numPoints * 3]; int[] meshIndex = new int[numPoints * 3];
@ -717,7 +705,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;
@ -862,7 +850,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);
@ -878,7 +866,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

@ -457,7 +457,7 @@ public class LwHttp implements HttpEngine {
for (int n = val; n > 0; n = n / 10, i++) for (int n = val; n > 0; n = n / 10, i++)
buf[pos + i] = (byte) ('0' + n % 10); buf[pos + i] = (byte) ('0' + n % 10);
ArrayUtils.reverse(buf, pos, pos + i); ArrayUtils.reverse(buf, pos, pos + i, 1);
return pos + i; return pos + i;
} }

View File

@ -1,5 +1,6 @@
/* /*
* Copyright 2013 Hannes Janetzek * Copyright 2013 Hannes Janetzek
* Copyright 2019 Gustl22
* *
* This file is part of the OpenScienceMap project (http://www.opensciencemap.org). * 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 <T> 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) { public static void reverse(short[] data, int left, int right, int stride) {
right -= 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) { while (left < right) {
byte tmp = data[left]; for (int i = 0; i < stride; i++) {
data[left] = data[right]; float tmp = data[left + i];
data[right] = tmp; 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;
} }
} }

View File

@ -66,6 +66,16 @@ public final class GeometryUtils {
return inside; 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) { public static float area(float ax, float ay, float bx, float by, float cx, float cy) {
float area = ((ax - cx) * (by - cy) float area = ((ax - cx) * (by - cy)
@ -107,6 +117,33 @@ public final class GeometryUtils {
return bisection; 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 a first vector
* @param b second 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, * Is polygon clockwise.
* negative for clockwise turn, and zero if the points are collinear. *
* @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) { 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]);
} }
/** /**