1e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai/* 2e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * Copyright (C) 2017 The Android Open Source Project 3e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * 4e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * Licensed under the Apache License, Version 2.0 (the "License"); 5e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * you may not use this file except in compliance with the License. 6e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * You may obtain a copy of the License at 7e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * 8e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * http://www.apache.org/licenses/LICENSE-2.0 9e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * 10e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * Unless required by applicable law or agreed to in writing, software 11e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * distributed under the License is distributed on an "AS IS" BASIS, 12e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * See the License for the specific language governing permissions and 14e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * limitations under the License. 15e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 16e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 17e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsaipackage com.android.layoutlib.bridge.shadowutil; 18e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 19e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsaiimport android.annotation.NonNull; 20e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 21e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsaipublic class SpotShadow { 22e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 23e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static float rayIntersectPoly(@NonNull float[] poly, int polyLength, float px, float py, 24e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx, float dy) { 25e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int p1 = polyLength - 1; 26e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int p2 = 0; p2 < polyLength; p2++) { 27e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p1x = poly[p1 * 2 + 0]; 28e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p1y = poly[p1 * 2 + 1]; 29e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p2x = poly[p2 * 2 + 0]; 30e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p2y = poly[p2 * 2 + 1]; 31e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float div = (dx * (p1y - p2y) + dy * p2x - dy * p1x); 32e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (div != 0) { 33e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float t = (dx * (p1y - py) + dy * px - dy * p1x) / (div); 34e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (t >= 0 && t <= 1) { 35e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float t2 = (p1x * (py - p2y) + p2x * (p1y - py) + px * (p2y - p1y)) / div; 36e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (t2 > 0) { 37e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return t2; 38e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 39e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 40e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 41e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p1 = p2; 42e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 43e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return Float.NaN; 44e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 45e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 46e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void centroid2d(@NonNull float[] poly, int len, @NonNull float[] ret) { 47e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float sumX = 0; 48e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float sumY = 0; 49e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int p1 = len - 1; 50e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float area = 0; 51e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int p2 = 0; p2 < len; p2++) { 52e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float x1 = poly[p1 * 2 + 0]; 53e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y1 = poly[p1 * 2 + 1]; 54e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float x2 = poly[p2 * 2 + 0]; 55e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y2 = poly[p2 * 2 + 1]; 56e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float a = (x1 * y2 - x2 * y1); 57e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai sumX += (x1 + x2) * a; 58e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai sumY += (y1 + y2) * a; 59e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai area += a; 60e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p1 = p2; 61e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 62e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 63e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float centroidX = sumX / (3 * area); 64e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float centroidY = sumY / (3 * area); 65e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[0] = centroidX; 66e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[1] = centroidY; 67e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 68e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 69e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 70e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * calculates the Centroid of a 3d polygon 71e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param poly The flatten 3d vertices coordinates of polygon, the format is like 72e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * [x0, y0, z0, x1, y1, z1, x2, ...] 73e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param len The number of polygon vertices. So the length of poly should be len * 3. 74e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param ret The array used to sotre the result. The length should be 3. 75e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 76e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void centroid3d(@NonNull float[] poly, int len, @NonNull float[] ret) { 77e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int n = len - 1; 78e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai double area = 0; 79e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai double cx = 0, cy = 0, cz = 0; 80e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 1; i < n; i++) { 81e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int k = i + 1; 82e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float a0 = poly[i * 3 + 0] - poly[0 * 3 + 0]; 83e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float a1 = poly[i * 3 + 1] - poly[0 * 3 + 1]; 84e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float a2 = poly[i * 3 + 2] - poly[0 * 3 + 2]; 85e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float b0 = poly[k * 3 + 0] - poly[0 * 3 + 0]; 86e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float b1 = poly[k * 3 + 1] - poly[0 * 3 + 1]; 87e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float b2 = poly[k * 3 + 2] - poly[0 * 3 + 2]; 88e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float c0 = a1 * b2 - b1 * a2; 89e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float c1 = a2 * b0 - b2 * a0; 90e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float c2 = a0 * b1 - b0 * a1; 91e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai double areaOfTriangle = Math.sqrt(c0 * c0 + c1 * c1 + c2 * c2); 92e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai area += areaOfTriangle; 93e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai cx += areaOfTriangle * (poly[i * 3 + 0] + poly[k * 3 + 0] + poly[0 * 3 + 0]); 94e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai cy += areaOfTriangle * (poly[i * 3 + 1] + poly[k * 3 + 1] + poly[0 * 3 + 1]); 95e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai cz += areaOfTriangle * (poly[i * 3 + 2] + poly[k * 3 + 2] + poly[0 * 3 + 2]); 96e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 97e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[0] = (float) (cx / (3 * area)); 98e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[1] = (float) (cy / (3 * area)); 99e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[2] = (float) (cz / (3 * area)); 100e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 101e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 102e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 103e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * Extracts the convex hull of a polygon. 104e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param points The vertices coordinates of polygon 105e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param pointsLength The number of polygon vertices. So the length of poly should be len * 3. 106e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param retPoly retPoly is at most the size of the input polygon 107e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @return The number of points in the retPolygon 108e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 109e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static int hull(@NonNull float[] points, int pointsLength, @NonNull float[] retPoly) { 110e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai quicksortX(points, 0, pointsLength - 1); 111e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int n = pointsLength; 112e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] lUpper = new float[n * 2]; 113e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[0] = points[0]; 114e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[1] = points[1]; 115e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[2] = points[2]; 116e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[3] = points[3]; 117e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 118e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int lUpperSize = 2; 119e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 120e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 2; i < n; i++) { 121e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[lUpperSize * 2 + 0] = points[i * 2 + 0]; 122e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[lUpperSize * 2 + 1] = points[i * 2 + 1]; 123e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpperSize++; 124e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 125e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (lUpperSize > 2 && 126e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai !rightTurn(lUpper[(lUpperSize - 3) * 2], lUpper[(lUpperSize - 3) * 2 + 1], 127e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[(lUpperSize - 2) * 2], lUpper[(lUpperSize - 2) * 2 + 1], 128e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[(lUpperSize - 1) * 2], lUpper[(lUpperSize - 1) * 2 + 1])) { 129e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai // Remove the middle point of the three last 130e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[(lUpperSize - 2) * 2 + 0] = lUpper[(lUpperSize - 1) * 2 + 0]; 131e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpper[(lUpperSize - 2) * 2 + 1] = lUpper[(lUpperSize - 1) * 2 + 1]; 132e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lUpperSize--; 133e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 134e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 135e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 136e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] lLower = new float[n * 2]; 137e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[0] = points[(n - 1) * 2 + 0]; 138e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[1] = points[(n - 1) * 2 + 1]; 139e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[2] = points[(n - 2) * 2 + 0]; 140e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[3] = points[(n - 2) * 2 + 1]; 141e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 142e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int lLowerSize = 2; 143e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 144e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = n - 3; i >= 0; i--) { 145e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[lLowerSize * 2 + 0] = points[i * 2 + 0]; 146e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[lLowerSize * 2 + 1] = points[i * 2 + 1]; 147e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLowerSize++; 148e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 149e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (lLowerSize > 2 && 150e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai !rightTurn(lLower[(lLowerSize - 3) * 2], lLower[(lLowerSize - 3) * 2 + 1], 151e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[(lLowerSize - 2) * 2], lLower[(lLowerSize - 2) * 2 + 1], 152e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[(lLowerSize - 1) * 2], lLower[(lLowerSize - 1) * 2 + 1])) { 153e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai // Remove the middle point of the three last 154e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[(lLowerSize - 2) * 2 + 0] = lLower[(lLowerSize - 1) * 2 + 0]; 155e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLower[(lLowerSize - 2) * 2 + 1] = lLower[(lLowerSize - 1) * 2 + 1]; 156e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lLowerSize--; 157e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 158e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 159e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 160e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int count = 0; 161e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < lUpperSize; i++) { 162e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retPoly[count * 2 + 0] = lUpper[i * 2 + 0]; 163e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retPoly[count * 2 + 1] = lUpper[i * 2 + 1]; 164e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 165e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 166e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 1; i < lLowerSize - 1; i++) { 167e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retPoly[count * 2 + 0] = lLower[i * 2 + 0]; 168e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retPoly[count * 2 + 1] = lLower[i * 2 + 1]; 169e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 170e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 171e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return count; 172e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 173e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 174e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static boolean rightTurn(float ax, float ay, float bx, float by, float cx, float cy) { 175e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax) > 0.00001; 176e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 177e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 178e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 179e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * calculates the intersection of poly1 with poly2 and put in poly2 180e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param poly1 The flatten 2d coordinates of polygon 181e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param poly1length The vertices number of poly1 182e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param poly2 The flatten 2d coordinates of polygon 183e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param poly2length The vertices number of poly2 184e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @return number of vertices in poly2 185e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 186e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static int intersection(@NonNull float[] poly1, int poly1length, @NonNull float[] poly2, 187e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int poly2length) { 188e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai makeClockwise(poly1, poly1length); 189e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai makeClockwise(poly2, poly2length); 190e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] poly = new float[(poly1length * poly2length + 2) * 2]; 191e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int count = 0; 192e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int pCount = 0; 193e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < poly1length; i++) { 194e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (pointInsidePolygon(poly1[i * 2 + 0], poly1[i * 2 + 1], poly2, poly2length)) { 195e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 0] = poly1[i * 2 + 0]; 196e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 1] = poly1[i * 2 + 1]; 197e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 198e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai pCount++; 199e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 200e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 201e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int fromP1 = pCount; 202e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < poly2length; i++) { 203e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (pointInsidePolygon(poly2[i * 2 + 0], poly2[i * 2 + 1], poly1, poly1length)) { 204e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 0] = poly2[i * 2 + 0]; 205e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 1] = poly2[i * 2 + 1]; 206e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 207e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 208e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 209e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int fromP2 = count - fromP1; 210e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (fromP1 == poly1length) { // use p1 211e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < poly1length; i++) { 212e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[i * 2 + 0] = poly1[i * 2 + 0]; 213e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[i * 2 + 1] = poly1[i * 2 + 1]; 214e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 215e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return poly1length; 216e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 217e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (fromP2 == poly2length) { // use p2 218e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return poly2length; 219e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 220e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] intersection = new float[2]; 221e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < poly2length; i++) { 222e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int j = 0; j < poly1length; j++) { 223e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int i1_by_2 = i * 2; 224e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int i2_by_2 = ((i + 1) % poly2length) * 2; 225e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int j1_by_2 = j * 2; 226e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int j2_by_2 = ((j + 1) % poly1length) * 2; 227e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai boolean found = 228e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai lineIntersection(poly2[i1_by_2 + 0], poly2[i1_by_2 + 1], poly2[i2_by_2 + 0], 229e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[i2_by_2 + 1], poly1[j1_by_2 + 0], poly1[j1_by_2 + 1], 230e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly1[j2_by_2 + 0], poly1[j2_by_2 + 1], intersection); 231e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (found) { 232e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 0] = intersection[0]; 233e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 1] = intersection[1]; 234e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 235e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } else { 236e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx = poly2[i * 2 + 0] - poly1[j * 2 + 0]; 237e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dy = poly2[i * 2 + 1] - poly1[j * 2 + 1]; 238e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 239e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (dx * dx + dy * dy < 0.01) { 240e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 0] = poly2[i * 2 + 0]; 241e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly[count * 2 + 1] = poly2[i * 2 + 1]; 242e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 243e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 244e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 245e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 246e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 247e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (count == 0) { 248e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return 0; 249e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 250e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float avgX = 0; 251e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float avgY = 0; 252e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < count; i++) { 253e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai avgX += poly[i * 2 + 0]; 254e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai avgY += poly[i * 2 + 1]; 255e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 256e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai avgX /= count; 257e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai avgY /= count; 258e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 259e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] ctr = new float[]{avgX, avgY}; 260e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai sort(poly, count, ctr); 261e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int size = count; 262e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 263e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[0] = poly[0]; 264e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[1] = poly[1]; 265e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 266e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count = 1; 267e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 1; i < size; i++) { 268e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx = poly[i * 2 + 0] - poly[(i - 1) * 2 + 0]; 269e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dy = poly[i * 2 + 1] - poly[(i - 1) * 2 + 1]; 270e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (dx * dx + dy * dy >= 0.01) { 271e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[count * 2 + 0] = poly[i * 2 + 0]; 272e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai poly2[count * 2 + 1] = poly[i * 2 + 1]; 273e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai count++; 274e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 275e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 276e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return count; 277e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 278e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 279e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai public static void sort(@NonNull float[] poly, int polyLength, @NonNull float[] ctr) { 280e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai quicksortCircle(poly, 0, polyLength - 1, ctr); 281e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 282e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 283e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai public static float angle(float x1, float y1, @NonNull float[] ctr) { 284e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return -(float) Math.atan2(x1 - ctr[0], y1 - ctr[1]); 285e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 286e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 287e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void swapPair(@NonNull float[] points, int i, int j) { 288e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float x = points[i * 2 + 0]; 289e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y = points[i * 2 + 1]; 290e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai points[i * 2 + 0] = points[j * 2 + 0]; 291e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai points[i * 2 + 1] = points[j * 2 + 1]; 292e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai points[j * 2 + 0] = x; 293e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai points[j * 2 + 1] = y; 294e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 295e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 296e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void quicksortCircle(@NonNull float[] points, int low, int high, 297e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai @NonNull float[] ctr) { 298e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int i = low, j = high; 299e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int p = low + (high - low) / 2; 300e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float pivot = angle(points[p * 2], points[p * 2 + 1], ctr); 301e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (i <= j) { 302e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (angle(points[i * 2 + 0], points[i * 2 + 1], ctr) < pivot) { 303e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai i++; 304e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 305e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (angle(points[j * 2 + 0], points[j * 2 + 1], ctr) > pivot) { 306e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai j--; 307e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 308e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (i <= j) { 309e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai swapPair(points, i, j); 310e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai i++; 311e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai j--; 312e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 313e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 314e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (low < j) { 315e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai quicksortCircle(points, low, j, ctr); 316e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 317e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (i < high) { 318e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai quicksortCircle(points, i, high, ctr); 319e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 320e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 321e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 322e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 323e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * This function do Quick Sort by comparing X axis only.<br> 324e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * Note that the input values of points are paired coordinates, e.g. {@code [x0, y0, x1, y1, x2, 325e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * y2, ...]).} 326e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param points The input point pairs. Every {@code (2 * i, 2 * i + 1)} points are pairs. 327e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param low lowest index used to do quick sort sort 328e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param high highest index used to do quick sort 329e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 330e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void quicksortX(@NonNull float[] points, int low, int high) { 331e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int i = low, j = high; 332e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int p = low + (high - low) / 2; 333e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float pivot = points[p * 2]; 334e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (i <= j) { 335e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (points[i * 2 + 0] < pivot) { 336e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai i++; 337e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 338e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai while (points[j * 2 + 0] > pivot) { 339e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai j--; 340e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 341e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 342e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (i <= j) { 343e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai swapPair(points, i, j); 344e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai i++; 345e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai j--; 346e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 347e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 348e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (low < j) { 349e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai quicksortX(points, low, j); 350e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 351e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (i < high) { 352e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai quicksortX(points, i, high); 353e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 354e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 355e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 356e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static boolean pointInsidePolygon(float x, float y, @NonNull float[] poly, int len) { 357e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai boolean c = false; 358e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float testX = x; 359e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float testY = y; 360e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0, j = len - 1; i < len; j = i++) { 361e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (((poly[i * 2 + 1] > testY) != (poly[j * 2 + 1] > testY)) && (testX < 362e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai (poly[j * 2 + 0] - poly[i * 2 + 0]) * (testY - poly[i * 2 + 1]) / 363e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai (poly[j * 2 + 1] - poly[i * 2 + 1]) + poly[i * 2 + 0])) { 364e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai c = !c; 365e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 366e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 367e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return c; 368e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 369e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 370e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void makeClockwise(@NonNull float[] polygon, int len) { 371e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (polygon == null || len == 0) { 372e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return; 373e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 374e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (!isClockwise(polygon, len)) { 375e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai reverse(polygon, len); 376e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 377e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 378e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 379e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static boolean isClockwise(@NonNull float[] polygon, int len) { 380e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float sum = 0; 381e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p1x = polygon[(len - 1) * 2 + 0]; 382e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p1y = polygon[(len - 1) * 2 + 1]; 383e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < len; i++) { 384e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p2x = polygon[i * 2 + 0]; 385e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float p2y = polygon[i * 2 + 1]; 386e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai sum += p1x * p2y - p2x * p1y; 387e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p1x = p2x; 388e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p1y = p2y; 389e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 390e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return sum < 0; 391e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 392e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 393e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void reverse(@NonNull float[] polygon, int len) { 394e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int n = len / 2; 395e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < n; i++) { 396e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float tmp0 = polygon[i * 2 + 0]; 397e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float tmp1 = polygon[i * 2 + 1]; 398e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int k = len - 1 - i; 399e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai polygon[i * 2 + 0] = polygon[k * 2 + 0]; 400e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai polygon[i * 2 + 1] = polygon[k * 2 + 1]; 401e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai polygon[k * 2 + 0] = tmp0; 402e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai polygon[k * 2 + 1] = tmp1; 403e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 404e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 405e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 406e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 407e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * Intersects two lines in parametric form. 408e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 409e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static final boolean lineIntersection(float x1, float y1, float x2, float y2, float x3, 410e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y3, float x4, float y4, @NonNull float[] ret) { 411e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float d = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4); 412e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (d == 0.000f) { 413e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return false; 414e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 415e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 416e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx = (x1 * y2 - y1 * x2); 417e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dy = (x3 * y4 - y3 * x4); 418e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float x = (dx * (x3 - x4) - (x1 - x2) * dy) / d; 419e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y = (dx * (y3 - y4) - (y1 - y2) * dy) / d; 420e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 421e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (((x - x1) * (x - x2) > 0.0000001) || ((x - x3) * (x - x4) > 0.0000001) || 422e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ((y - y1) * (y - y2) > 0.0000001) || ((y - y3) * (y - y4) > 0.0000001)) { 423e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return false; 424e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 425e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[0] = x; 426e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[1] = y; 427e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return true; 428e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 429e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 430e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai @NonNull 431e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai public static float[] calculateLight(float size, int points, float x, float y, float height) { 432e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] ret = new float[points * 3]; 433e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < points; i++) { 434e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai double angle = 2 * i * Math.PI / points; 435e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[i * 3 + 0] = (float) Math.cos(angle) * size + x; 436e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[i * 3 + 1] = (float) Math.sin(angle) * size + y; 437e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai ret[i * 3 + 2] = (height); 438e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 439e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return ret; 440e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 441e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 442e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 443e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai layers indicates the number of circular strips to generate. 444e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai Strength is how dark a shadow to generate. 445e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 446e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 447e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * This calculates a collection of triangles that represent the shadow cast by a polygonal 448e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * light source (lightPoly) hitting a convex polygon (poly). 449e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param lightPoly The flatten 3d coordinates of light 450e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param lightPolyLength The vertices number of light polygon. 451e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param poly The flatten 3d coordinates of item 452e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param polyLength The vertices number of light polygon. 453e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param rays defines the number of points around the perimeter of the shadow to generate 454e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param layers The number of shadow's fading. 455e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param strength The factor of the black color of shadow. 456e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param retStrips Used to store the calculated shadow strength 457e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @return true if the params is able to calculate a shadow, else false. 458e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 459e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai public static boolean calcShadow(@NonNull float[] lightPoly, int lightPolyLength, 460e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai @NonNull float[] poly, int polyLength, int rays, int layers, float strength, 461e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai @NonNull float[] retStrips) { 462e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] shadowRegion = new float[lightPolyLength * polyLength * 2]; 463e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] outline = new float[polyLength * 2]; 464e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] umbra = new float[polyLength * lightPolyLength * 2]; 465e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int umbraLength = 0; 466e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 467e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int k = 0; 468e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int j = 0; j < lightPolyLength; j++) { 469e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int m = 0; 470e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < polyLength; i++) { 471e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float t = lightPoly[j * 3 + 2] - poly[i * 3 + 2]; 472e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (t == 0) { 473e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return false; 474e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 475e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai t = lightPoly[j * 3 + 2] / t; 476e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float x = lightPoly[j * 3 + 0] - t * (lightPoly[j * 3 + 0] - poly[i * 3 + 0]); 477e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y = lightPoly[j * 3 + 1] - t * (lightPoly[j * 3 + 1] - poly[i * 3 + 1]); 478e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 479e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai shadowRegion[k * 2 + 0] = x; 480e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai shadowRegion[k * 2 + 1] = y; 481e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai outline[m * 2 + 0] = x; 482e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai outline[m * 2 + 1] = y; 483e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 484e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai k++; 485e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai m++; 486e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 487e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (umbraLength == 0) { 488e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai System.arraycopy(outline, 0, umbra, 0, polyLength); 489e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai umbraLength = polyLength; 490e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } else { 491e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai umbraLength = intersection(outline, polyLength, umbra, umbraLength); 492e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (umbraLength == 0) { 493e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai break; 494e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 495e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 496e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 497e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int shadowRegionLength = k; 498e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 499e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] penumbra = new float[k * 2]; 500e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int penumbraLength = hull(shadowRegion, shadowRegionLength, penumbra); 501e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (umbraLength < 3) {// no real umbra make a fake one 502e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] p = new float[3]; 503e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centroid3d(lightPoly, lightPolyLength, p); 504e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] centShadow = new float[polyLength * 2]; 505e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < polyLength; i++) { 506e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float t = p[2] - poly[i * 3 + 2]; 507e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if (t == 0) { 508e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return false; 509e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 510e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai t = p[2] / t; 511e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float x = p[0] - t * (p[0] - poly[i * 3 + 0]); 512e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float y = p[1] - t * (p[1] - poly[i * 3 + 1]); 513e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 514e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centShadow[i * 2 + 0] = x; 515e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centShadow[i * 2 + 1] = y; 516e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 517e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] c = new float[2]; 518e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centroid2d(centShadow, polyLength, c); 519e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < polyLength; i++) { 520e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centShadow[i * 2 + 0] = (c[0] * 9 + centShadow[i * 2 + 0]) / 10; 521e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centShadow[i * 2 + 1] = (c[1] * 9 + centShadow[i * 2 + 1]) / 10; 522e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 523e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai umbra = centShadow; // fake umbra 524e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai umbraLength = polyLength; // same size as the original polygon 525e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 526e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 527e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai triangulateConcentricPolygon(penumbra, penumbraLength, umbra, umbraLength, rays, layers, 528e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai strength, retStrips); 529e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return true; 530e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 531e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 532e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai /** 533e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * triangulate concentric circles. 534e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * This takes the inner and outer polygons of the umbra and penumbra and triangulates it. 535e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param penumbra The 2d flatten vertices of penumbra polygons. 536e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param penumbraLength The number of vertices in penumbra. 537e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param umbra The 2d flatten vertices of umbra polygons. 538e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param umbraLength The number of vertices in umbra. 539e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param rays defines the number of points around the perimeter of the shadow to generate 540e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param layers The number of shadow's fading. 541e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param strength The factor of the black color of shadow. 542e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai * @param retStrips Used to store the calculated shadow strength. 543e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai */ 544e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai private static void triangulateConcentricPolygon(@NonNull float[] penumbra, int penumbraLength, 545e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai @NonNull float[] umbra, int umbraLength, int rays, int layers, float strength, 546e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai @NonNull float[] retStrips) { 547e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int rings = layers + 1; 548e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai double step = Math.PI * 2 / rays; 549e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] retXY = new float[2]; 550e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai centroid2d(umbra, umbraLength, retXY); 551e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float cx = retXY[0]; 552e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float cy = retXY[1]; 553e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 554e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] t1 = new float[rays]; 555e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float[] t2 = new float[rays]; 556e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 557e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < rays; i++) { 558e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx = (float) Math.cos(Math.PI / 4 + step * i); 559e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dy = (float) Math.sin(Math.PI / 4 + step * i); 560e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai t2[i] = rayIntersectPoly(umbra, umbraLength, cx, cy, dx, dy); 561e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai t1[i] = rayIntersectPoly(penumbra, penumbraLength, cx, cy, dx, dy); 562e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 563e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 564e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int p = 0; 565e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai // Calculate the vertex 566e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int r = 0; r < layers; r++) { 567e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int startP = p; 568e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int i = 0; i < rays; i++) { 569e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx = (float) Math.cos(Math.PI / 4 + step * i); 570e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dy = (float) Math.sin(Math.PI / 4 + step * i); 571e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 572e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int j = r; j < (r + 2); j++) { 573e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float jf = j / (float) (rings - 1); 574e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float t = t1[i] + jf * (t2[i] - t1[i]); 575e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float op = (jf + 1 - 1 / (1 + (t - t1[i]) * (t - t1[i]))) / 2; 576e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 0] = dx * t + cx; 577e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 1] = dy * t + cy; 578e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 2] = jf * op * strength; 579e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p++; 580e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 581e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 582e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 583e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 0] = retStrips[startP * 3 + 0]; 584e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 1] = retStrips[startP * 3 + 1]; 585e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 2] = retStrips[startP * 3 + 2]; 586e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p++; 587e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai startP++; 588e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 0] = retStrips[startP * 3 + 0]; 589e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 1] = retStrips[startP * 3 + 1]; 590e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 2] = retStrips[startP * 3 + 2]; 591e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p++; 592e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 593e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int oldP = p - 1; 594e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 0] = retStrips[oldP * 3 + 0]; 595e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 1] = retStrips[oldP * 3 + 1]; 596e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 2] = retStrips[oldP * 3 + 2]; 597e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p++; 598e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 599e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai // Skip the first point here, then make it same as last point later. 600e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai oldP = p; 601e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p++; 602e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai for (int k = 0; k < rays; k++) { 603e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai int i = k / 2; 604e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai if ((k & 1) == 1) { // traverse the inside in a zig zag pattern 605e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai // for strips 606e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai i = rays - i - 1; 607e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 608e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dx = (float) Math.cos(Math.PI / 4 + step * i); 609e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float dy = (float) Math.sin(Math.PI / 4 + step * i); 610e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 611e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float jf = 1; 612e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 613e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float t = t1[i] + jf * (t2[i] - t1[i]); 614e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai float op = (jf + 1 - 1 / (1 + (t - t1[i]) * (t - t1[i]))) / 2; 615e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 616e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 0] = dx * t + cx; 617e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 1] = dy * t + cy; 618e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 2] = jf * op * strength; 619e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p++; 620e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 621e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai p = oldP; 622e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 0] = retStrips[oldP * 3 + 0]; 623e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 1] = retStrips[oldP * 3 + 1]; 624e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai retStrips[p * 3 + 2] = retStrips[oldP * 3 + 2]; 625e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 626e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai 627e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai public static int getStripSize(int rays, int layers) { 628e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai return (2 + rays + ((layers) * 2 * (rays + 1))); 629e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai } 630e18bf49be68e1d38a2b6ac3ab6a50aeab3352660Charlie Tsai} 631