diff --git a/CHANGES b/CHANGES index d91012d7..7531ed81 100644 --- a/CHANGES +++ b/CHANGES @@ -13,6 +13,7 @@ **Runtime** - [BREAK CHANGE] `TextureArrayCpuPolygonSpriteBatch` is now the default batch implementation - [BREAK CHANGE] New `MainItemComponent#uniqueId` management, change from integer to a random string +- First integration of Spine's BoundingBoxAttachment with Box2D for skeletal collision detection - Chained Entities and Spine' SkeletonRenderSeparator - Improved PhysicsActions. Add `PhysicsActions#transformTo` and `PhysicsActions#transformBy` - Fixed physic's step diff --git a/h2d-libgdx-spine-extension b/h2d-libgdx-spine-extension index dc7d17c7..e1fc8e8a 160000 --- a/h2d-libgdx-spine-extension +++ b/h2d-libgdx-spine-extension @@ -1 +1 @@ -Subproject commit dc7d17c7432f5e3b81f86a59e28297953d932e1f +Subproject commit e1fc8e8ae852d3bc841647264122c2551521b1f1 diff --git a/hyperlap2d-runtime-libgdx b/hyperlap2d-runtime-libgdx index e45ff31c..36ae3b7c 160000 --- a/hyperlap2d-runtime-libgdx +++ b/hyperlap2d-runtime-libgdx @@ -1 +1 @@ -Subproject commit e45ff31cdee8174975b5e7286bcc314a547a9670 +Subproject commit 36ae3b7cf83b5b502ebe4d8b3517348cdabd44a6 diff --git a/src/main/java/games/rednblack/editor/controller/commands/ChangePolygonVertexPositionCommand.java b/src/main/java/games/rednblack/editor/controller/commands/ChangePolygonVertexPositionCommand.java index fd802b5f..6bd08a1c 100644 --- a/src/main/java/games/rednblack/editor/controller/commands/ChangePolygonVertexPositionCommand.java +++ b/src/main/java/games/rednblack/editor/controller/commands/ChangePolygonVertexPositionCommand.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.utils.IntSet; import games.rednblack.editor.controller.SandboxCommand; import games.rednblack.editor.controller.commands.component.UpdatePolygonVerticesCommand; import games.rednblack.editor.renderer.components.shape.PolygonShapeComponent; +import games.rednblack.editor.renderer.utils.poly.PolygonRuntimeUtils; import games.rednblack.editor.utils.poly.PolygonUtils; import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; import games.rednblack.editor.view.ui.followers.PolygonFollower; @@ -50,10 +51,10 @@ public class ChangePolygonVertexPositionCommand extends SandboxCommand { Vector2[] pointsArray = points.toArray(); IntSet intersections = PolygonUtils.checkForIntersection(anchor, points, intersectionProblems); if(intersections == null) { - if(PolygonUtils.isPolygonCCW(pointsArray)){ + if(PolygonRuntimeUtils.isPolygonCCW(pointsArray)){ points.reverse(); } - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(polygonShapeComponent.vertices.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(polygonShapeComponent.vertices.toArray()); UpdatePolygonVerticesCommand.payload(currentCommandPayload, polygonShapeComponent.vertices, polygonShapeComponent.polygonizedVertices); Facade.getInstance().sendNotification(MsgAPI.ACTION_UPDATE_MESH_DATA, currentCommandPayload); diff --git a/src/main/java/games/rednblack/editor/controller/commands/DeletePolygonVertexCommand.java b/src/main/java/games/rednblack/editor/controller/commands/DeletePolygonVertexCommand.java index a9d227e6..0fc3de7b 100644 --- a/src/main/java/games/rednblack/editor/controller/commands/DeletePolygonVertexCommand.java +++ b/src/main/java/games/rednblack/editor/controller/commands/DeletePolygonVertexCommand.java @@ -6,7 +6,7 @@ import com.kotcrab.vis.ui.util.dialog.Dialogs; import games.rednblack.editor.controller.SandboxCommand; import games.rednblack.editor.controller.commands.component.UpdatePolygonVerticesCommand; import games.rednblack.editor.renderer.components.shape.PolygonShapeComponent; -import games.rednblack.editor.utils.poly.PolygonUtils; +import games.rednblack.editor.renderer.utils.poly.PolygonRuntimeUtils; import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; import games.rednblack.editor.view.ui.followers.PolygonFollower; import games.rednblack.h2d.common.MsgAPI; @@ -47,7 +47,7 @@ public class DeletePolygonVertexCommand extends SandboxCommand { polygonShapeComponent.vertices.removeIndex(anchor); follower.setSelectedAnchor(0); - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(polygonShapeComponent.vertices.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(polygonShapeComponent.vertices.toArray()); if(polygonShapeComponent.polygonizedVertices == null) { // restore from backup diff --git a/src/main/java/games/rednblack/editor/controller/commands/UpdatePolygonDataCommand.java b/src/main/java/games/rednblack/editor/controller/commands/UpdatePolygonDataCommand.java index 96861a62..796c87d0 100644 --- a/src/main/java/games/rednblack/editor/controller/commands/UpdatePolygonDataCommand.java +++ b/src/main/java/games/rednblack/editor/controller/commands/UpdatePolygonDataCommand.java @@ -3,7 +3,7 @@ package games.rednblack.editor.controller.commands; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; import games.rednblack.editor.renderer.components.shape.PolygonShapeComponent; -import games.rednblack.editor.utils.poly.PolygonUtils; +import games.rednblack.editor.renderer.utils.poly.PolygonRuntimeUtils; import games.rednblack.editor.utils.runtime.EntityUtils; import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; import games.rednblack.h2d.common.MsgAPI; @@ -49,10 +49,10 @@ public class UpdatePolygonDataCommand extends EntityModifyRevertibleCommand { private void checkPolygon(PolygonShapeComponent polygonShapeComponent) { if (!polygonShapeComponent.openEnded) { Array points = polygonShapeComponent.vertices; - if(PolygonUtils.isPolygonCCW(points.toArray())){ + if(PolygonRuntimeUtils.isPolygonCCW(points.toArray())){ points.reverse(); } - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(points.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(points.toArray()); } } } diff --git a/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonVerticesCommand.java b/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonVerticesCommand.java index c2298efa..a52aa3a1 100644 --- a/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonVerticesCommand.java +++ b/src/main/java/games/rednblack/editor/controller/commands/component/UpdatePolygonVerticesCommand.java @@ -5,6 +5,7 @@ import com.badlogic.gdx.utils.Array; import games.rednblack.editor.controller.commands.EntityModifyRevertibleCommand; import games.rednblack.editor.renderer.components.TextureRegionComponent; import games.rednblack.editor.renderer.components.shape.PolygonShapeComponent; +import games.rednblack.editor.renderer.utils.poly.PolygonRuntimeUtils; import games.rednblack.editor.utils.runtime.EntityUtils; import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; import games.rednblack.h2d.common.MsgAPI; @@ -88,11 +89,7 @@ public class UpdatePolygonVerticesCommand extends EntityModifyRevertibleCommand } public static Array cloneData(Array data) { - Array clone = new Array<>(true, data.size, Vector2.class); - for (Vector2 vector2 : data) { - clone.add(vector2.cpy()); - } - return clone; + return PolygonRuntimeUtils.cloneData(data); } public static Vector2[][] cloneData(Vector2[][] data) { Vector2[][] newData = new Vector2[data.length][]; diff --git a/src/main/java/games/rednblack/editor/utils/poly/Clipper.java b/src/main/java/games/rednblack/editor/utils/poly/Clipper.java deleted file mode 100644 index e5414aa9..00000000 --- a/src/main/java/games/rednblack/editor/utils/poly/Clipper.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * ****************************************************************************** - * * Copyright 2015 See AUTHORS file. - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * ***************************************************************************** - */ - -package games.rednblack.editor.utils.poly; - -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Array; -import games.rednblack.editor.utils.poly.earclipping.bayazit.BayazitDecomposer; -import games.rednblack.editor.utils.poly.earclipping.ewjordan.EwjordanDecomposer; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * - * @author Aurelien Ribon | http://www.aurelienribon.com/ - */ -public class Clipper { - public enum Polygonizer {EWJORDAN, BAYAZIT} - - public static Vector2[][] polygonize(Polygonizer polygonizer, Vector2[] points) { - Vector2[][] polygons = null; - - if (PolygonUtils.isPolygonCCW(points)) { - List vertices = Arrays.asList(points); - Collections.reverse(vertices); - points = vertices.toArray(new Vector2[0]); - } - - switch (polygonizer) { - case EWJORDAN: - polygons = EwjordanDecomposer.decompose(points); - break; - - case BAYAZIT: - Array tmpPoints = new Array(points.length); - tmpPoints.addAll(points); - - Array> tmpPolygons; - - try { - tmpPolygons = BayazitDecomposer.ConvexPartition(tmpPoints); - } catch (Exception ex) { - tmpPolygons = null; - } - - if (tmpPolygons != null) { - polygons = new Vector2[tmpPolygons.size][]; - for (int i = 0; i < tmpPolygons.size; i++) { - polygons[i] = new Vector2[tmpPolygons.get(i).size]; - for (int ii = 0; ii < tmpPolygons.get(i).size; ii++) - polygons[i][ii] = new Vector2(tmpPolygons.get(i).get(ii)); - } - } - break; - } - - if (polygons != null) polygons = sliceForMax8Vertices(polygons); - return polygons; - } - - private static Vector2[][] sliceForMax8Vertices(Vector2[][] polygons) { - for (int i = 0; i < polygons.length; i++) { - Vector2[] poly = polygons[i]; - if (poly.length > 8) { - int limit = poly.length < 15 ? poly.length / 2 + 1 : 8; - Vector2[] newPoly1 = new Vector2[limit]; - Vector2[] newPoly2 = new Vector2[poly.length - limit + 2]; - System.arraycopy(poly, 0, newPoly1, 0, limit); - System.arraycopy(poly, limit - 1, newPoly2, 0, poly.length - limit + 1); - newPoly2[newPoly2.length - 1] = poly[0].cpy(); - - Vector2[][] newPolys = new Vector2[polygons.length + 1][]; - if (i > 0) { - System.arraycopy(polygons, 0, newPolys, 0, i); - } - if (i < polygons.length - 1) { - System.arraycopy(polygons, i + 1, newPolys, i + 2, polygons.length - i - 1); - } - newPolys[i] = newPoly1; - newPolys[i + 1] = newPoly2; - polygons = newPolys; - - i -= 1; - } - } - return polygons; - } -} diff --git a/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java b/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java index e7b57d8a..4b0509bb 100644 --- a/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java +++ b/src/main/java/games/rednblack/editor/utils/poly/PolygonUtils.java @@ -24,37 +24,11 @@ import com.badlogic.gdx.utils.*; import games.rednblack.editor.utils.Vector2Pool; import games.rednblack.editor.view.stage.Sandbox; -import java.util.HashSet; - /** * * @author Aurelien Ribon | http://www.aurelienribon.com/ */ public class PolygonUtils { - public static float getPolygonSignedArea(Vector2[] points) { - if (points.length < 3) - return 0; - - float sum = 0; - for (int i = 0; i < points.length; i++) { - Vector2 p1 = points[i]; - Vector2 p2 = i != points.length-1 ? points[i+1] : points[0]; - sum += (p1.x * p2.y) - (p1.y * p2.x); - } - return 0.5f * sum; - } - - public static float getPolygonArea(Vector2[] points) { - return Math.abs(getPolygonSignedArea(points)); - } - - public static boolean isPolygonCCW(Vector2[] points) { - return getPolygonSignedArea(points) > 0; - } - - public static Vector2[][] polygonize(Vector2[] vertices) { - return Clipper.polygonize(Clipper.Polygonizer.EWJORDAN, vertices); - } public static boolean intersectSegments(Array points, int index1, int index2, int index3, int index4) { Vector2 intersectionPoint = Pools.obtain(Vector2.class).set(points.get(index1)); diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/bayazit/BayazitDecomposer.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/bayazit/BayazitDecomposer.java deleted file mode 100644 index f47520ba..00000000 --- a/src/main/java/games/rednblack/editor/utils/poly/earclipping/bayazit/BayazitDecomposer.java +++ /dev/null @@ -1,701 +0,0 @@ -/* - * ****************************************************************************** - * * Copyright 2015 See AUTHORS file. - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * ***************************************************************************** - */ - -package games.rednblack.editor.utils.poly.earclipping.bayazit; - -// Taken from BayazitDecomposer.cs (FarseerPhysics.Common.Decomposition.BayazitDecomposer) -// at http://farseerphysics.codeplex.com - -import com.badlogic.gdx.math.Vector2; -import com.badlogic.gdx.utils.Array; -import games.rednblack.editor.controller.commands.component.UpdatePolygonVerticesCommand; - -import java.security.InvalidParameterException; - -/// -/// Convex decomposition algorithm created by Mark Bayazit (http://mnbayazit.com/) -/// For more information about this algorithm, see http://mnbayazit.com/406/bayazit -/// -public class BayazitDecomposer { - - public static final float Epsilon = 1.192092896e-07f; - public static int MaxPolygonVertices = 8; - - public static Vector2 Cross(Vector2 a, float s) { - return new Vector2(s * a.y, -s * a.x); - } - - private static Vector2 At(int i, Array vertices) { - int s = vertices.size; - return vertices.get(i < 0 ? s - (-i % s) : i % s); - } - - private static Array Copy(int i, int j, Array vertices) { - Array p = new Array(); - while (j < i) - j += vertices.size; - // p.reserve(j - i + 1); - for (; i <= j; ++i) { - p.add(At(i, vertices)); - } - return p; - } - - public static float GetSignedArea(Array vect) { - int i; - float area = 0; - for (i = 0; i < vect.size; i++) { - int j = (i + 1) % vect.size; - area += vect.get(i).x * vect.get(j).y; - area -= vect.get(i).y * vect.get(j).x; - } - area /= 2.0f; - return area; - } - - public static float GetSignedArea(Vector2[] vect) { - int i; - float area = 0; - for (i = 0; i < vect.length; i++) { - int j = (i + 1) % vect.length; - area += vect[i].x * vect[j].y; - area -= vect[i].y * vect[j].x; - } - area /= 2.0f; - return area; - } - - public static Boolean IsCounterClockWise(Array vect) { - // We just return true for lines - if (vect.size < 3) - return true; - return (GetSignedArea(vect) > 0.0f); - } - - public static Boolean IsCounterClockWise(Vector2[] vect) { - // We just return true for lines - if (vect.length < 3) - return true; - return (GetSignedArea(vect) > 0.0f); - } - - // / - // / Decompose the polygon into several smaller non-concave polygon. - // / If the polygon is already convex, it will return the original polygon, - // unless it is over Settings.MaxPolygonVertices. - // / Precondition: Counter Clockwise polygon - // / - // / - // / - public static Array> ConvexPartition(Array vertices) { - // We force it to CCW as it is a precondition in this algorithm. - // vertices.ForceCounterClockWise(); - if (!IsCounterClockWise(vertices)) { - // Collections.reverse(vertices); - vertices.reverse(); - // Array reversed = new Array(vertices.size); - // for (int i = vertices.size - 1; i <= 0; i--) { - // reversed.add(vertices.get(i)); - // } - // vertices = reversed; - } - Array> list = new Array>(); - float d, lowerDist, upperDist; - Vector2 p; - Vector2 lowerInt = new Vector2(); - Vector2 upperInt = new Vector2(); // intersection points - int lowerIndex = 0, upperIndex = 0; - Array lowerPoly, upperPoly; - for (int i = 0; i < vertices.size; ++i) { - if (Reflex(i, vertices)) { - lowerDist = upperDist = Float.MAX_VALUE; // std::numeric_limits::max(); - for (int j = 0; j < vertices.size; ++j) { - // if line intersects with an edge - if (Left(At(i - 1, vertices), At(i, vertices), - At(j, vertices)) - && RightOn(At(i - 1, vertices), At(i, vertices), - At(j - 1, vertices))) { - // find the point of intersection - p = LineIntersect(At(i - 1, vertices), At(i, vertices), - At(j, vertices), At(j - 1, vertices)); - if (Right(At(i + 1, vertices), At(i, vertices), p)) { - // make sure it's inside the poly - d = SquareDist(At(i, vertices), p); - if (d < lowerDist) { - // keep only the closest intersection - lowerDist = d; - lowerInt = p; - lowerIndex = j; - } - } - } - if (Left(At(i + 1, vertices), At(i, vertices), - At(j + 1, vertices)) - && RightOn(At(i + 1, vertices), At(i, vertices), - At(j, vertices))) { - p = LineIntersect(At(i + 1, vertices), At(i, vertices), - At(j, vertices), At(j + 1, vertices)); - if (Left(At(i - 1, vertices), At(i, vertices), p)) { - d = SquareDist(At(i, vertices), p); - if (d < upperDist) { - upperDist = d; - upperIndex = j; - upperInt = p; - } - } - } - } - // if there are no vertices to connect to, choose a point in the - // middle - if (lowerIndex == (upperIndex + 1) % vertices.size) { - Vector2 sp = new Vector2((lowerInt.x + upperInt.x) / 2, - (lowerInt.y + upperInt.y) / 2); - lowerPoly = Copy(i, upperIndex, vertices); - lowerPoly.add(sp); - upperPoly = Copy(lowerIndex, i, vertices); - upperPoly.add(sp); - } else { - double highestScore = 0, bestIndex = lowerIndex; - while (upperIndex < lowerIndex) - upperIndex += vertices.size; - for (int j = lowerIndex; j <= upperIndex; ++j) { - if (CanSee(i, j, vertices)) { - double score = 1 / (SquareDist(At(i, vertices), - At(j, vertices)) + 1); - if (Reflex(j, vertices)) { - if (RightOn(At(j - 1, vertices), - At(j, vertices), At(i, vertices)) - && LeftOn(At(j + 1, vertices), - At(j, vertices), - At(i, vertices))) { - score += 3; - } else { - score += 2; - } - } else { - score += 1; - } - if (score > highestScore) { - bestIndex = j; - highestScore = score; - } - } - } - lowerPoly = Copy(i, (int) bestIndex, vertices); - upperPoly = Copy((int) bestIndex, i, vertices); - } - list.addAll(ConvexPartition(lowerPoly)); - list.addAll(ConvexPartition(upperPoly)); - return list; - } - } - // polygon is already convex - if (vertices.size > MaxPolygonVertices) { - lowerPoly = Copy(0, vertices.size / 2, vertices); - upperPoly = Copy(vertices.size / 2, 0, vertices); - list.addAll(ConvexPartition(lowerPoly)); - list.addAll(ConvexPartition(upperPoly)); - } else - list.add(vertices); - // The polygons are not guaranteed to be with collinear points. We - // remove - // them to be sure. - for (int i = 0; i < list.size; i++) { - list.set(i, SimplifyTools.CollinearSimplify(list.get(i), 0)); - } - // Remove empty vertice collections - for (int i = list.size - 1; i >= 0; i--) { - if (list.get(i).size == 0) - list.removeIndex(i); - } - return list; - } - - private static Boolean CanSee(int i, int j, Array vertices) { - if (Reflex(i, vertices)) { - if (LeftOn(At(i, vertices), At(i - 1, vertices), At(j, vertices)) - && RightOn(At(i, vertices), At(i + 1, vertices), - At(j, vertices))) - return false; - } else { - if (RightOn(At(i, vertices), At(i + 1, vertices), At(j, vertices)) - || LeftOn(At(i, vertices), At(i - 1, vertices), - At(j, vertices))) - return false; - } - if (Reflex(j, vertices)) { - if (LeftOn(At(j, vertices), At(j - 1, vertices), At(i, vertices)) - && RightOn(At(j, vertices), At(j + 1, vertices), - At(i, vertices))) - return false; - } else { - if (RightOn(At(j, vertices), At(j + 1, vertices), At(i, vertices)) - || LeftOn(At(j, vertices), At(j - 1, vertices), - At(i, vertices))) - return false; - } - for (int k = 0; k < vertices.size; ++k) { - if ((k + 1) % vertices.size == i || k == i - || (k + 1) % vertices.size == j || k == j) { - continue; // ignore incident edges - } - Vector2 intersectionPoint = new Vector2(); - if (LineIntersect(At(i, vertices), At(j, vertices), - At(k, vertices), At(k + 1, vertices), true, true, - intersectionPoint)) { - return false; - } - } - return true; - } - - public static Vector2 LineIntersect(Vector2 p1, Vector2 p2, Vector2 q1, - Vector2 q2) { - Vector2 i = new Vector2(); - float a1 = p2.y - p1.y; - float b1 = p1.x - p2.x; - float c1 = a1 * p1.x + b1 * p1.y; - float a2 = q2.y - q1.y; - float b2 = q1.x - q2.x; - float c2 = a2 * q1.x + b2 * q1.y; - float det = a1 * b2 - a2 * b1; - if (!FloatEquals(det, 0)) { - // lines are not parallel - i.x = (b2 * c1 - b1 * c2) / det; - i.y = (a1 * c2 - a2 * c1) / det; - } - return i; - } - - public static Boolean FloatEquals(float value1, float value2) { - return Math.abs(value1 - value2) <= Epsilon; - } - - // / - // / This method detects if two line segments (or lines) intersect, - // / and, if so, the point of intersection. Use the - // and - // / parameters to set whether the - // intersection point - // / must be on the first and second line segments. Setting these - // / both to true means you are doing a line-segment to line-segment - // / intersection. Setting one of them to true means you are doing a - // / line to line-segment intersection test, and so on. - // / Note: If two line segments are coincident, then - // / no intersection is detected (there are actually - // / infinite intersection points). - // / Author: Jeremy Bell - // / - // / The first point of the first line segment. - // / The second point of the first line - // segment. - // / The first point of the second line - // segment. - // / The second point of the second line - // segment. - // / This is set to the intersection - // / point if an intersection is detected. - // / Set this to true to require that the - // / intersection point be on the first line segment. - // / Set this to true to require that the - // / intersection point be on the second line segment. - // / True if an intersection is detected, false - // otherwise. - public static Boolean LineIntersect(Vector2 point1, Vector2 point2, - Vector2 point3, Vector2 point4, Boolean firstIsSegment, - Boolean secondIsSegment, Vector2 point) { - point = new Vector2(); - // these are reused later. - // each lettered sub-calculation is used twice, except - // for b and d, which are used 3 times - float a = point4.y - point3.y; - float b = point2.x - point1.x; - float c = point4.x - point3.x; - float d = point2.y - point1.y; - // denominator to solution of linear system - float denom = (a * b) - (c * d); - // if denominator is 0, then lines are parallel - if (!(denom >= -Epsilon && denom <= Epsilon)) { - float e = point1.y - point3.y; - float f = point1.x - point3.x; - float oneOverDenom = 1.0f / denom; - // numerator of first equation - float ua = (c * e) - (a * f); - ua *= oneOverDenom; - // check if intersection point of the two lines is on line segment 1 - if (!firstIsSegment || ua >= 0.0f && ua <= 1.0f) { - // numerator of second equation - float ub = (b * e) - (d * f); - ub *= oneOverDenom; - // check if intersection point of the two lines is on line - // segment 2 - // means the line segments intersect, since we know it is on - // segment 1 as well. - if (!secondIsSegment || ub >= 0.0f && ub <= 1.0f) { - // check if they are coincident (no collision in this case) - if (ua != 0f || ub != 0f) { - // There is an intersection - point.x = point1.x + ua * b; - point.y = point1.y + ua * d; - return true; - } - } - } - } - return false; - } - - // precondition: ccw - private static Boolean Reflex(int i, Array vertices) { - return Right(i, vertices); - } - - private static Boolean Right(int i, Array vertices) { - return Right(At(i - 1, vertices), At(i, vertices), At(i + 1, vertices)); - } - - private static Boolean Left(Vector2 a, Vector2 b, Vector2 c) { - return Area(a, b, c) > 0; - } - - private static Boolean LeftOn(Vector2 a, Vector2 b, Vector2 c) { - return Area(a, b, c) >= 0; - } - - private static Boolean Right(Vector2 a, Vector2 b, Vector2 c) { - return Area(a, b, c) < 0; - } - - private static Boolean RightOn(Vector2 a, Vector2 b, Vector2 c) { - return Area(a, b, c) <= 0; - } - - public static float Area(Vector2 a, Vector2 b, Vector2 c) { - return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y); - } - - private static float SquareDist(Vector2 a, Vector2 b) { - float dx = b.x - a.x; - float dy = b.y - a.y; - return dx * dx + dy * dy; - } -} - -class SimplifyTools { - private static Boolean[] _usePt; - private static double _distanceTolerance; - - // / - // / Removes all collinear points on the polygon. - // / - // / The polygon that needs simplification. - // / The collinearity tolerance. - // / A simplified polygon. - public static Array CollinearSimplify(Array vertices, - float collinearityTolerance) { - // We can't simplify polygons under 3 vertices - if (vertices.size < 3) - return vertices; - Array simplified = new Array(); - for (int i = 0; i < vertices.size; i++) { - int prevId = i - 1; - if (prevId < 0) - prevId = vertices.size - 1; - int nextId = i + 1; - if (nextId >= vertices.size) - nextId = 0; - Vector2 prev = vertices.get(prevId); - Vector2 current = vertices.get(i); - Vector2 next = vertices.get(nextId); - // If they collinear, continue - if (Collinear(prev, current, next, collinearityTolerance)) - continue; - simplified.add(current); - } - return simplified; - } - - public static Boolean Collinear(Vector2 a, Vector2 b, Vector2 c, - float tolerance) { - return FloatInRange(BayazitDecomposer.Area(a, b, c), -tolerance, - tolerance); - } - - public static Boolean FloatInRange(float value, float min, float max) { - return (value >= min && value <= max); - } - - // / - // / Removes all collinear points on the polygon. - // / Has a default bias of 0 - // / - // / The polygon that needs simplification. - // / A simplified polygon. - public static Array CollinearSimplify(Array vertices) { - return CollinearSimplify(vertices, 0); - } - - // / - // / Ramer-Douglas-Peucker polygon simplification algorithm. This is the - // general recursive version that does not use the - // / speed-up technique by using the Melkman convex hull. - // / - // / If you pass in 0, it will remove all collinear points - // / - // / The simplified polygon - public static Array DouglasPeuckerSimplify( - Array vertices, float distanceTolerance) { - _distanceTolerance = distanceTolerance; - _usePt = new Boolean[vertices.size]; - for (int i = 0; i < vertices.size; i++) - _usePt[i] = true; - SimplifySection(vertices, 0, vertices.size - 1); - Array result = new Array(); - for (int i = 0; i < vertices.size; i++) - if (_usePt[i]) - result.add(vertices.get(i)); - return result; - } - - private static void SimplifySection(Array vertices, int i, int j) { - if ((i + 1) == j) - return; - Vector2 A = vertices.get(i); - Vector2 B = vertices.get(j); - double maxDistance = -1.0; - int maxIndex = i; - for (int k = i + 1; k < j; k++) { - double distance = DistancePointLine(vertices.get(k), A, B); - if (distance > maxDistance) { - maxDistance = distance; - maxIndex = k; - } - } - if (maxDistance <= _distanceTolerance) - for (int k = i + 1; k < j; k++) - _usePt[k] = false; - else { - SimplifySection(vertices, i, maxIndex); - SimplifySection(vertices, maxIndex, j); - } - } - - private static double DistancePointPoint(Vector2 p, Vector2 p2) { - double dx = p.x - p2.x; - double dy = p.y - p2.x; - return Math.sqrt(dx * dx + dy * dy); - } - - private static double DistancePointLine(Vector2 p, Vector2 A, Vector2 B) { - // if start == end, then use point-to-point distance - if (A.x == B.x && A.y == B.y) - return DistancePointPoint(p, A); - // otherwise use comp.graphics.algorithms Frequently Asked Questions - // method - /* - * (1) AC dot AB r = --------- ||AB||^2 r has the following meaning: r=0 - * Point = A r=1 Point = B r<0 Point is on the backward extension of AB - * r>1 Point is on the forward extension of AB 0= 1.0) - return DistancePointPoint(p, B); - /* - * (2) (Ay-Cy)(Bx-Ax)-(Ax-Cx)(By-Ay) s = ----------------------------- - * Curve^2 Then the distance from C to Point = |s|*Curve. - */ - double s = ((A.y - p.y) * (B.x - A.x) - (A.x - p.x) * (B.y - A.y)) - / ((B.x - A.x) * (B.x - A.x) + (B.y - A.y) * (B.y - A.y)); - return Math.abs(s) - * Math.sqrt(((B.x - A.x) * (B.x - A.x) + (B.y - A.y) - * (B.y - A.y))); - } - - // From physics2d.net - public static Array ReduceByArea(Array vertices, - float areaTolerance) { - if (vertices.size <= 3) - return vertices; - if (areaTolerance < 0) { - throw new InvalidParameterException( - "areaTolerance: must be equal to or greater then zero."); - } - Array result = new Array(); - Vector2 v1, v2, v3; - float old1, old2, new1; - v1 = vertices.get(vertices.size - 2); - v2 = vertices.get(vertices.size - 1); - areaTolerance *= 2; - for (int index = 0; index < vertices.size; ++index, v2 = v3) { - if (index == vertices.size - 1) { - if (result.size == 0) { - throw new InvalidParameterException( - "areaTolerance: The tolerance is too high!"); - } - v3 = result.get(0); - } else { - v3 = vertices.get(index); - } - old1 = Cross(v1, v2); - old2 = Cross(v2, v3); - new1 = Cross(v1, v3); - if (Math.abs(new1 - (old1 + old2)) > areaTolerance) { - result.add(v2); - v1 = v2; - } - } - return result; - } - - public static Float Cross(Vector2 a, Vector2 b) { - return a.x * b.y - a.y * b.x; - } - - // From Eric Jordan's convex decomposition library - // / - // / Merges all parallel edges in the list of vertices - // / - // / The vertices. - // / The tolerance. - public static void MergeParallelEdges(Array vertices, - float tolerance) { - if (vertices.size <= 3) - return; // Can't do anything useful here to a triangle - Boolean[] mergeMe = new Boolean[vertices.size]; - int newNVertices = vertices.size; - // Gather points to process - for (int i = 0; i < vertices.size; ++i) { - int lower = (i == 0) ? (vertices.size - 1) : (i - 1); - int middle = i; - int upper = (i == vertices.size - 1) ? (0) : (i + 1); - float dx0 = vertices.get(middle).x - vertices.get(lower).x; - float dy0 = vertices.get(middle).y - vertices.get(lower).y; - float dx1 = vertices.get(upper).y - vertices.get(middle).x; - float dy1 = vertices.get(upper).y - vertices.get(middle).y; - float norm0 = (float) Math.sqrt(dx0 * dx0 + dy0 * dy0); - float norm1 = (float) Math.sqrt(dx1 * dx1 + dy1 * dy1); - if (!(norm0 > 0.0f && norm1 > 0.0f) && newNVertices > 3) { - // Merge identical points - mergeMe[i] = true; - --newNVertices; - } - dx0 /= norm0; - dy0 /= norm0; - dx1 /= norm1; - dy1 /= norm1; - float cross = dx0 * dy1 - dx1 * dy0; - float dot = dx0 * dx1 + dy0 * dy1; - if (Math.abs(cross) < tolerance && dot > 0 && newNVertices > 3) { - mergeMe[i] = true; - --newNVertices; - } else - mergeMe[i] = false; - } - if (newNVertices == vertices.size || newNVertices == 0) - return; - int currIndex = 0; - // Copy the vertices to a new list and clear the old - Array oldVertices = UpdatePolygonVerticesCommand.cloneData(vertices); - vertices.clear(); - for (int i = 0; i < oldVertices.size; ++i) { - if (mergeMe[i] || newNVertices == 0 || currIndex == newNVertices) - continue; - // Debug.Assert(currIndex < newNVertices); - vertices.add(oldVertices.get(i)); - ++currIndex; - } - } - - // Misc - // / - // / Merges the identical points in the polygon. - // / - // / The vertices. - // / - public static Array MergeIdenticalPoints(Array vertices) { - Array results = new Array(); - for (int i = 0; i < vertices.size; i++) { - Vector2 vOriginal = vertices.get(i); - - boolean alreadyExists = false; - for (int j = 0; j < results.size; j++) { - Vector2 v = results.get(j); - if (vOriginal.equals(v)) { - alreadyExists = true; - break; - } - } - if (!alreadyExists) - results.add(vertices.get(i)); - } - return results; - } - - // / - // / Reduces the polygon by distance. - // / - // / The vertices. - // / The distance between points. Points closer than - // this will be 'joined'. - // / - public static Array ReduceByDistance(Array vertices, - float distance) { - // We can't simplify polygons under 3 vertices - if (vertices.size < 3) - return vertices; - Array simplified = new Array(); - for (int i = 0; i < vertices.size; i++) { - Vector2 current = vertices.get(i); - int ii = i + 1; - if (ii >= vertices.size) - ii = 0; - Vector2 next = vertices.get(ii); - Vector2 diff = new Vector2(next.x - current.x, next.y - current.y); - // If they are closer than the distance, continue - if (diff.len2() <= distance) - continue; - simplified.add(current); - } - return simplified; - } - - // / - // / Reduces the polygon by removing the Nth vertex in the vertices list. - // / - // / The vertices. - // / The Nth point to remove. Example: 5. - // / - public static Array ReduceByNth(Array vertices, int nth) { - // We can't simplify polygons under 3 vertices - if (vertices.size < 3) - return vertices; - if (nth == 0) - return vertices; - Array result = new Array(vertices.size); - for (int i = 0; i < vertices.size; i++) { - if (i % nth == 0) - continue; - result.add(vertices.get(i)); - } - return result; - } -} diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/EwjordanDecomposer.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/EwjordanDecomposer.java deleted file mode 100644 index 565960f9..00000000 --- a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/EwjordanDecomposer.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * ****************************************************************************** - * * Copyright 2015 See AUTHORS file. - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * ***************************************************************************** - */ - -package games.rednblack.editor.utils.poly.earclipping.ewjordan; - -import com.badlogic.gdx.math.Vector2; - -/** - * Original code from EwJordan (http://www.ewjordan.com/earClip/) - */ -public class EwjordanDecomposer { - public static Vector2[][] decompose(Vector2[] points) { - int vNum = points.length; - float[] xv = new float[vNum]; - float[] yv = new float[vNum]; - - for (int i = 0; i < vNum; i++) { - xv[i] = points[i].x; - yv[i] = points[i].y; - } - - Triangle[] tempTriangles = triangulatePolygon(xv, yv, vNum); - Polygon[] tempPolygons = polygonizeTriangles(tempTriangles); - - if (tempPolygons == null) - return null; - - Vector2[][] polygons = new Vector2[tempPolygons.length][]; - for (int i = 0; i < tempPolygons.length; i++) { - polygons[i] = new Vector2[tempPolygons[i].nVertices]; - for (int ii = 0; ii < tempPolygons[i].nVertices; ii++) - polygons[i][ii] = new Vector2(tempPolygons[i].x[ii], tempPolygons[i].y[ii]); - } - - return polygons; - } - - // ------------------------------------------------------------------------- - - private static Triangle[] triangulatePolygon(float[] xv, float[] yv, int vNum) { - if (vNum < 3) - return null; - - Triangle[] buffer = new Triangle[vNum]; - int bufferSize = 0; - float[] xrem = new float[vNum]; - float[] yrem = new float[vNum]; - for (int i = 0; i < vNum; ++i) { - xrem[i] = xv[i]; - yrem[i] = yv[i]; - } - - while (vNum > 3) { - int earIndex = -1; - for (int i = 0; i < vNum; ++i) { - if (isEar(i, xrem, yrem)) { - earIndex = i; - break; - } - } - - if (earIndex == -1) - return null; - - --vNum; - float[] newx = new float[vNum]; - float[] newy = new float[vNum]; - int currDest = 0; - for (int i = 0; i < vNum; ++i) { - if (currDest == earIndex) { - ++currDest; - } - newx[i] = xrem[currDest]; - newy[i] = yrem[currDest]; - ++currDest; - } - - int under = (earIndex == 0) ? (xrem.length - 1) : (earIndex - 1); - int over = (earIndex == xrem.length - 1) ? 0 : (earIndex + 1); - - Triangle toAdd = new Triangle(xrem[earIndex], yrem[earIndex], xrem[over], yrem[over], xrem[under], yrem[under]); - buffer[bufferSize] = toAdd; - ++bufferSize; - - xrem = newx; - yrem = newy; - } - Triangle toAdd = new Triangle(xrem[1], yrem[1], xrem[2], yrem[2], xrem[0], yrem[0]); - buffer[bufferSize] = toAdd; - ++bufferSize; - - Triangle[] res = new Triangle[bufferSize]; - System.arraycopy(buffer, 0, res, 0, bufferSize); - return res; - } - - private static Polygon[] polygonizeTriangles(Triangle[] triangulated) { - Polygon[] polys; - int polyIndex = 0; - - if (triangulated == null) - return null; - - polys = new Polygon[triangulated.length]; - boolean[] covered = new boolean[triangulated.length]; - for (int i = 0; i < triangulated.length; i++) - covered[i] = false; - - boolean notDone = true; - - while (notDone) { - int currTri = -1; - for (int i = 0; i < triangulated.length; i++) { - if (!covered[i]) { - currTri = i; - break; - } - } - - if (currTri == -1) { - notDone = false; - } else { - Polygon poly = new Polygon(triangulated[currTri]); - covered[currTri] = true; - for (int i = 0; i < triangulated.length; i++) { - if (covered[i]) - continue; - - Polygon newP = poly.add(triangulated[i]); - if (newP == null) - continue; - - if (newP.isConvex()) { - poly = newP; - covered[i] = true; - } - } - polys[polyIndex] = poly; - polyIndex++; - } - } - - Polygon[] ret = new Polygon[polyIndex]; - System.arraycopy(polys, 0, ret, 0, polyIndex); - return ret; - } - - private static boolean isEar(int i, float[] xv, float[] yv) { - float dx0, dy0, dx1, dy1; - dx0 = dy0 = dx1 = dy1 = 0; - - if (i >= xv.length || i < 0 || xv.length < 3) - return false; - - int upper = i + 1; - int lower = i - 1; - - if (i == 0) { - dx0 = xv[0] - xv[xv.length - 1]; - dy0 = yv[0] - yv[yv.length - 1]; - dx1 = xv[1] - xv[0]; - dy1 = yv[1] - yv[0]; - lower = xv.length - 1; - } else if (i == xv.length - 1) { - dx0 = xv[i] - xv[i - 1]; - dy0 = yv[i] - yv[i - 1]; - dx1 = xv[0] - xv[i]; - dy1 = yv[0] - yv[i]; - upper = 0; - } else { - dx0 = xv[i] - xv[i - 1]; - dy0 = yv[i] - yv[i - 1]; - dx1 = xv[i + 1] - xv[i]; - dy1 = yv[i + 1] - yv[i]; - } - - float cross = dx0 * dy1 - dx1 * dy0; - if (cross > 0) - return false; - - Triangle myTri = new Triangle(xv[i], yv[i], xv[upper], yv[upper], xv[lower], yv[lower]); - for (int j = 0; j < xv.length; ++j) { - if (j == i || j == lower || j == upper) - continue; - if (myTri.isInside(xv[j], yv[j])) - return false; - } - - return true; - } -} diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Polygon.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Polygon.java deleted file mode 100644 index 2bc44026..00000000 --- a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Polygon.java +++ /dev/null @@ -1,150 +0,0 @@ -/* - * ****************************************************************************** - * * Copyright 2015 See AUTHORS file. - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * ***************************************************************************** - */ - -package games.rednblack.editor.utils.poly.earclipping.ewjordan; - -/** - * - * @author EwJordan (http://www.ewjordan.com/earClip/) - */ -public class Polygon { - public float[] x; - public float[] y; - public int nVertices; - - public Polygon(float[] _x, float[] _y) { - nVertices = _x.length; - x = new float[nVertices]; - y = new float[nVertices]; - for (int i = 0; i < nVertices; ++i) { - x[i] = _x[i]; - y[i] = _y[i]; - } - } - - public Polygon(Triangle t) { - this(t.x, t.y); - } - - public void set(Polygon p) { - nVertices = p.nVertices; - x = new float[nVertices]; - y = new float[nVertices]; - for (int i = 0; i < nVertices; ++i) { - x[i] = p.x[i]; - y[i] = p.y[i]; - } - } - - public boolean isConvex() { - boolean isPositive = false; - for (int i = 0; i < nVertices; ++i) { - int lower = (i == 0) ? (nVertices - 1) : (i - 1); - int middle = i; - int upper = (i == nVertices - 1) ? (0) : (i + 1); - float dx0 = x[middle] - x[lower]; - float dy0 = y[middle] - y[lower]; - float dx1 = x[upper] - x[middle]; - float dy1 = y[upper] - y[middle]; - float cross = dx0 * dy1 - dx1 * dy0; - //Cross product should have same sign - //for each vertex if poly is convex. - boolean newIsP = (cross > 0) ? true : false; - if (i == 0) { - isPositive = newIsP; - } else if (isPositive != newIsP) { - return false; - } - } - return true; - } - - /* - * Tries to add a triangle to the polygon. - * Returns null if it can't connect properly. - * Assumes bitwise equality of join vertices. - */ - public Polygon add(Triangle t) { - //First, find vertices that connect - int firstP = -1; - int firstT = -1; - int secondP = -1; - int secondT = -1; - for (int i = 0; i < nVertices; i++) { - if (t.x[0] == x[i] && t.y[0] == y[i]) { - if (firstP == -1) { - firstP = i; - firstT = 0; - } else { - secondP = i; - secondT = 0; - } - } else if (t.x[1] == x[i] && t.y[1] == y[i]) { - if (firstP == -1) { - firstP = i; - firstT = 1; - } else { - secondP = i; - secondT = 1; - } - } else if (t.x[2] == x[i] && t.y[2] == y[i]) { - if (firstP == -1) { - firstP = i; - firstT = 2; - } else { - secondP = i; - secondT = 2; - } - } - } - //Fix ordering if first should be last vertex of poly - if (firstP == 0 && secondP == nVertices - 1) { - firstP = nVertices - 1; - secondP = 0; - } - - //Didn't find it - if (secondP == -1) { - return null; - } - - //Find tip index on triangle - int tipT = 0; - if (tipT == firstT || tipT == secondT) { - tipT = 1; - } - if (tipT == firstT || tipT == secondT) { - tipT = 2; - } - - float[] newx = new float[nVertices + 1]; - float[] newy = new float[nVertices + 1]; - int currOut = 0; - for (int i = 0; i < nVertices; i++) { - newx[currOut] = x[i]; - newy[currOut] = y[i]; - if (i == firstP) { - ++currOut; - newx[currOut] = t.x[tipT]; - newy[currOut] = t.y[tipT]; - } - ++currOut; - } - return new Polygon(newx, newy); - } -} diff --git a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Triangle.java b/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Triangle.java deleted file mode 100644 index c06c822e..00000000 --- a/src/main/java/games/rednblack/editor/utils/poly/earclipping/ewjordan/Triangle.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * ****************************************************************************** - * * Copyright 2015 See AUTHORS file. - * * - * * Licensed under the Apache License, Version 2.0 (the "License"); - * * you may not use this file except in compliance with the License. - * * You may obtain a copy of the License at - * * - * * http://www.apache.org/licenses/LICENSE-2.0 - * * - * * Unless required by applicable law or agreed to in writing, software - * * distributed under the License is distributed on an "AS IS" BASIS, - * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * * See the License for the specific language governing permissions and - * * limitations under the License. - * ***************************************************************************** - */ - -package games.rednblack.editor.utils.poly.earclipping.ewjordan; - -/** - * - * @author EwJordan (http://www.ewjordan.com/earClip/) - */ -public class Triangle { - public float[] x; - public float[] y; - - public Triangle(float x1, float y1, float x2, float y2, float x3, float y3) { - x = new float[3]; - y = new float[3]; - float dx1 = x2 - x1; - float dx2 = x3 - x1; - float dy1 = y2 - y1; - float dy2 = y3 - y1; - float cross = dx1 * dy2 - dx2 * dy1; - boolean ccw = (cross > 0); - if (ccw) { - x[0] = x1; - x[1] = x2; - x[2] = x3; - y[0] = y1; - y[1] = y2; - y[2] = y3; - } else { - x[0] = x1; - x[1] = x3; - x[2] = x2; - y[0] = y1; - y[1] = y3; - y[2] = y2; - } - } - - public boolean isInside(float _x, float _y) { - float vx2 = _x - x[0]; - float vy2 = _y - y[0]; - float vx1 = x[1] - x[0]; - float vy1 = y[1] - y[0]; - float vx0 = x[2] - x[0]; - float vy0 = y[2] - y[0]; - - float dot00 = vx0 * vx0 + vy0 * vy0; - float dot01 = vx0 * vx1 + vy0 * vy1; - float dot02 = vx0 * vx2 + vy0 * vy2; - float dot11 = vx1 * vx1 + vy1 * vy1; - float dot12 = vx1 * vx2 + vy1 * vy2; - float invDenom = 1f / (dot00 * dot11 - dot01 * dot01); - float u = (dot11 * dot02 - dot01 * dot12) * invDenom; - float v = (dot00 * dot12 - dot01 * dot02) * invDenom; - - return ((u > 0) && (v > 0) && (u + v < 1)); - } -} diff --git a/src/main/java/games/rednblack/editor/view/stage/tools/PolygonTool.java b/src/main/java/games/rednblack/editor/view/stage/tools/PolygonTool.java index 2c911fb9..ac2b50e2 100644 --- a/src/main/java/games/rednblack/editor/view/stage/tools/PolygonTool.java +++ b/src/main/java/games/rednblack/editor/view/stage/tools/PolygonTool.java @@ -26,6 +26,7 @@ import games.rednblack.editor.controller.commands.AddComponentToItemCommand; import games.rednblack.editor.controller.commands.RemoveComponentFromItemCommand; import games.rednblack.editor.controller.commands.component.UpdatePolygonVerticesCommand; import games.rednblack.editor.renderer.components.shape.PolygonShapeComponent; +import games.rednblack.editor.renderer.utils.poly.PolygonRuntimeUtils; import games.rednblack.editor.utils.KeyBindingsLayout; import games.rednblack.editor.utils.poly.PolygonUtils; import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; @@ -132,10 +133,10 @@ public class PolygonTool extends SelectionTool implements PolygonTransformationL if (!polygonShapeComponent.openEnded) { IntSet intersections = PolygonUtils.checkForIntersection(vertexIndex, points, intersectionProblems); if(intersections == null) { - if(PolygonUtils.isPolygonCCW(points.toArray())){ + if(PolygonRuntimeUtils.isPolygonCCW(points.toArray())){ points.reverse(); } - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(points.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(points.toArray()); } else { // restore from backup polygonShapeComponent.vertices = UpdatePolygonVerticesCommand.cloneData(verticesBackup); @@ -156,7 +157,7 @@ public class PolygonTool extends SelectionTool implements PolygonTransformationL polygonShapeComponent.vertices.insert(vertexIndex, new Vector2(x, y)); if (!polygonShapeComponent.openEnded) - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(polygonShapeComponent.vertices.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(polygonShapeComponent.vertices.toArray()); follower.update(); follower.draggingAnchorId = vertexIndex; @@ -195,7 +196,7 @@ public class PolygonTool extends SelectionTool implements PolygonTransformationL // check if any of near lines intersect IntSet intersections = PolygonUtils.checkForIntersection(anchor, points, intersectionProblems); if(intersections == null) { - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(points.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(points.toArray()); follower.setProblems(null); } else { follower.setProblems(intersections); @@ -252,7 +253,7 @@ public class PolygonTool extends SelectionTool implements PolygonTransformationL follower.setSelectedAnchor(follower.getSelectedAnchorId() - 1); if (!polygonShapeComponent.openEnded) { - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(polygonShapeComponent.vertices.toArray()); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(polygonShapeComponent.vertices.toArray()); if(polygonShapeComponent.polygonizedVertices == null) { // restore from backup diff --git a/src/main/java/games/rednblack/editor/view/ui/dialog/AutoTraceDialogMediator.java b/src/main/java/games/rednblack/editor/view/ui/dialog/AutoTraceDialogMediator.java index 5f0d49bc..aa8580f3 100644 --- a/src/main/java/games/rednblack/editor/view/ui/dialog/AutoTraceDialogMediator.java +++ b/src/main/java/games/rednblack/editor/view/ui/dialog/AutoTraceDialogMediator.java @@ -5,7 +5,7 @@ import com.badlogic.gdx.utils.Array; import com.kotcrab.vis.ui.util.dialog.Dialogs; import games.rednblack.editor.renderer.components.shape.PolygonShapeComponent; import games.rednblack.editor.renderer.components.TextureRegionComponent; -import games.rednblack.editor.utils.poly.PolygonUtils; +import games.rednblack.editor.renderer.utils.poly.PolygonRuntimeUtils; import games.rednblack.editor.utils.poly.tracer.Tracer; import games.rednblack.editor.utils.runtime.SandboxComponentRetriever; import games.rednblack.editor.view.stage.Sandbox; @@ -71,7 +71,7 @@ public class AutoTraceDialogMediator extends Mediator { .flatMap(Stream::of) .toArray(Vector2[]::new); polygonShapeComponent.vertices = new Array<>(points); - polygonShapeComponent.polygonizedVertices = PolygonUtils.polygonize(points); + polygonShapeComponent.polygonizedVertices = PolygonRuntimeUtils.polygonize(points); FollowersUIMediator followersUIMediator = Facade.getInstance().retrieveMediator(FollowersUIMediator.NAME); BasicFollower follower = followersUIMediator.getFollower(entity);