public void setColor(int color) { Pixmap pix = new Pixmap(1, 1, Pixmap.Format.RGBA8888); pix.setColor(color); pix.fill(); Texture tex = new Texture(pix); TextureRegion region = new TextureRegion(tex); Point p1 = (Point) parent.getPoints().toArray()[0]; Point p2 = (Point) parent.getPoints().toArray()[1]; Point p3 = (Point) parent.getPoints().toArray()[2]; Point p4 = (Point) parent.getPoints().toArray()[3]; Point p5 = (Point) parent.getPoints().toArray()[4]; Point p6 = (Point) parent.getPoints().toArray()[5]; float[] vertices = new float[]{( float) p1.getCoordinateX(), (float)p1.getCoordinateY(), (float)p2.getCoordinateX(), (float)p2.getCoordinateY(), (float)p3.getCoordinateX(), (float)p3.getCoordinateY(), (float) p4.getCoordinateX(), (float)p4.getCoordinateY(), (float)p5.getCoordinateX(), (float)p5.getCoordinateY(), (float)p6.getCoordinateX(), (float)p6.getCoordinateY()}; EarClippingTriangulator triangulator = new EarClippingTriangulator(); ShortArray triangleIndices = triangulator.computeTriangles(vertices); PolygonRegion polygonRegion = new PolygonRegion(region, vertices, triangleIndices.toArray()); sprite = new PolygonSprite(polygonRegion); }
/** Removes all triangles with a centroid outside the specified hull, which may be concave. Note some triangulations may have * triangles whose centroid is inside the hull but a portion is outside. */ public void trim (ShortArray triangles, float[] points, float[] hull, int offset, int count) { short[] trianglesArray = triangles.items; for (int i = triangles.size - 1; i >= 0; i -= 3) { int p1 = trianglesArray[i - 2] * 2; int p2 = trianglesArray[i - 1] * 2; int p3 = trianglesArray[i] * 2; GeometryUtils.triangleCentroid(points[p1], points[p1 + 1], points[p2], points[p2 + 1], points[p3], points[p3 + 1], centroid); if (!Intersector.isPointInPolygon(hull, offset, count, centroid.x, centroid.y)) { triangles.removeIndex(i); triangles.removeIndex(i - 1); triangles.removeIndex(i - 2); } } }
private void triangulate () { int[] vertexTypes = this.vertexTypes.items; while (vertexCount > 3) { int earTipIndex = findEarTip(); cutEarTip(earTipIndex); // The type of the two vertices adjacent to the clipped vertex may have changed. int previousIndex = previousIndex(earTipIndex); int nextIndex = earTipIndex == vertexCount ? 0 : earTipIndex; vertexTypes[previousIndex] = classifyVertex(previousIndex); vertexTypes[nextIndex] = classifyVertex(nextIndex); } if (vertexCount == 3) { ShortArray triangles = this.triangles; short[] indices = this.indices; triangles.add(indices[0]); triangles.add(indices[1]); triangles.add(indices[2]); } }
@Override public void write(Kryo kryo, Output output, ShortArray array) { output.writeVarInt(array.size, true); output.writeBoolean(array.ordered); for (int i = 0; i < array.size; i++) { output.writeShort(array.get(i)); } }
@Override public ShortArray read(Kryo kryo, Input input, Class<ShortArray> type) { int length = input.readVarInt(true); boolean ordered = input.readBoolean(); ShortArray array = new ShortArray(ordered, length); for (int i = 0; i < length; i++) { array.add(input.readShort()); } return array; }
private Multigraph<GameRoom, NoDuplicateEdge> getGraphFromTriangulation(ShortArray trianglesIndices, Array<GameRoom> rooms) { Gdx.app.log("GraphGenerator", " --> Generating graph from triangulation"); Multigraph<GameRoom, NoDuplicateEdge> graph = new Multigraph<>(NoDuplicateEdge.class); int indexCount = trianglesIndices.size; for (int i = 2; i < indexCount; i += 3) { short index1 = trianglesIndices.get(i - 2); short index2 = trianglesIndices.get(i - 1); short index3 = trianglesIndices.get(i); GameRoom room1 = rooms.get(index1); GameRoom room2 = rooms.get(index2); GameRoom room3 = rooms.get(index3); graph.addVertex(room1); graph.addVertex(room2); graph.addVertex(room3); if (!graph.containsEdge(room1, room2)) graph.addEdge(room1, room2); if (!graph.containsEdge(room2, room3)) graph.addEdge(room2, room3); if (!graph.containsEdge(room3, room1)) graph.addEdge(room3, room1); } return graph; }
/** Draw bounding boxes (hitbox/collision detection) */ private void drawBounds() { boolean polyTriangles = false; for (Entity entity : objects) { BoundsComponent bounds = Mappers.bounds.get(entity); TransformComponent t = Mappers.transform.get(entity); if (bounds != null) { //draw Axis-Aligned bounding box Rectangle rect = bounds.poly.getBoundingRectangle(); shape.setColor(1, 1, 0, 1); shape.rect(t.pos.x - rect.width/2, t.pos.y - rect.height/2, rect.width, rect.height); //draw Orientated bounding box shape.setColor(1, 0, 0, 1); shape.polygon(bounds.poly.getTransformedVertices()); if (polyTriangles) { // draw triangles shape.setColor(Color.BLUE); FloatArray points = new FloatArray(bounds.poly.getTransformedVertices()); ShortArray triangles = tri.computeTriangles(points, false); for (int i = 0; i < triangles.size; i += 3) { int p1 = triangles.get(i) * 2; int p2 = triangles.get(i + 1) * 2; int p3 = triangles.get(i + 2) * 2; shape.triangle( points.get(p1), points.get(p1 + 1), points.get(p2), points.get(p2 + 1), points.get(p3), points.get(p3 + 1)); } } } } }
/** Triangulates the given (convex or concave) simple polygon to a list of triangle vertices. * @param vertices pairs describing vertices of the polygon, in either clockwise or counterclockwise order. * @return triples of triangle indices in clockwise order. Note the returned array is reused for later calls to the same * method. */ public ShortArray computeTriangles (float[] vertices, int offset, int count) { this.vertices = vertices; int vertexCount = this.vertexCount = count / 2; ShortArray indicesArray = this.indicesArray; indicesArray.clear(); indicesArray.ensureCapacity(vertexCount); indicesArray.size = vertexCount; short[] indices = this.indices = indicesArray.items; if (areVerticesClockwise(vertices, offset, count)) { for (short i = 0; i < vertexCount; i++) indices[i] = i; } else { for (int i = 0, n = vertexCount - 1; i < vertexCount; i++) indices[i] = (short)(n - i); // Reversed. } IntArray vertexTypes = this.vertexTypes; vertexTypes.clear(); vertexTypes.ensureCapacity(vertexCount); for (int i = 0, n = vertexCount; i < n; ++i) vertexTypes.add(classifyVertex(i)); // A polygon with n vertices has a triangulation of n-2 triangles. ShortArray triangles = this.triangles; triangles.clear(); triangles.ensureCapacity(Math.max(0, vertexCount - 2) * 3); triangulate(); return triangles; }
private void cutEarTip (int earTipIndex) { short[] indices = this.indices; ShortArray triangles = this.triangles; triangles.add(indices[previousIndex(earTipIndex)]); triangles.add(indices[earTipIndex]); triangles.add(indices[nextIndex(earTipIndex)]); indicesArray.removeIndex(earTipIndex); vertexTypes.removeIndex(earTipIndex); vertexCount--; }
/** @param concave the concave polygon to triangulate * @return an array of triangles representing the given concave polygon * @see com.badlogic.gdx.math.EarClippingTriangulator#computeTriangles(float[]) */ public static Polygon[] triangulate(Polygon concave) { Vector2[] polygonVertices = toVector2Array(concave.getTransformedVertices()); ShortArray indices = new EarClippingTriangulator().computeTriangles(toFloatArray(polygonVertices)); Vector2[] vertices = new Vector2[indices.size]; for(int i = 0; i < indices.size; i++) vertices[i] = polygonVertices[indices.get(i)]; return toPolygonArray(vertices, 3); }
/** Returns a new array containing the remaining keys. */ public ShortArray toArray () { ShortArray array = new ShortArray(true, map.size); while (hasNext) array.add(next()); return array; }
public Multigraph<GameRoom, NoDuplicateEdge> generateMinimalSpanningTree(Array<GameCell> cells, float remainingEdgesMultiplier) { Gdx.app.log("GraphGenerator", "----------------- Generating minimal spanning tree -----------------"); Array<GameRoom> rooms = GameMap.extractRooms(cells); ShortArray trianglesIndices = generateTrianglesIndices(cells); Multigraph<GameRoom, NoDuplicateEdge> graph = getGraphFromTriangulation(trianglesIndices, rooms); Set<NoDuplicateEdge> minEdges = new KruskalMinimumSpanningTree(graph).getMinimumSpanningTreeEdgeSet(); // Set<NoDuplicateEdge> minEdges = new PrimMinimumSpanningTree(graph).getMinimumSpanningTreeEdgeSet(); minimumSpanningTreeFromGraph(graph, minEdges, remainingEdgesMultiplier); Gdx.app.log("GraphGenerator", " --> Graph is now a minimal spanning tree. Edge count: " + graph.edgeSet().size()); return graph; }
/** @see #computeTriangles(float[], int, int, boolean) */ public ShortArray computeTriangles (FloatArray points, boolean sorted) { return computeTriangles(points.items, 0, points.size, sorted); }
/** @see #computeTriangles(float[], int, int, boolean) */ public ShortArray computeTriangles (float[] polygon, boolean sorted) { return computeTriangles(polygon, 0, polygon.length, sorted); }
/** @see #computeTriangles(float[], int, int) */ public ShortArray computeTriangles (FloatArray vertices) { return computeTriangles(vertices.items, 0, vertices.size); }
/** @see #computeTriangles(float[], int, int) */ public ShortArray computeTriangles (float[] vertices) { return computeTriangles(vertices, 0, vertices.length); }
private ShortArray generateTrianglesIndices(Array<GameCell> cells) { Gdx.app.log("GraphGenerator", " --> Generating Delaunay Triangulation"); float[] roomCenterPoints = getRoomCenterPoints(cells); return new DelaunayTriangulator().computeTriangles(roomCenterPoints, false); }
/** * Returns an array of vertex indices that the define the triangles which * make up this {@link Polygon} * * @return Array of triangle indices */ public ShortArray getTriangles() { trianglesDirtyCheck(); return triangles; }