Java tutorial
/* * Copyright 2014 MovingBlocks * * 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 org.terasology.polyworld; import java.awt.Color; import java.awt.Graphics2D; import java.awt.geom.Path2D; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.util.List; import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.terasology.math.Rect2i; import org.terasology.math.geom.BaseVector2f; import org.terasology.polyworld.graph.Graph; import org.terasology.polyworld.graph.Region; import org.terasology.polyworld.graph.Triangle; import com.google.common.base.Stopwatch; import com.google.common.collect.Lists; /** * Creates a image-based lookup table to map individual pixel to triangles * of the regions in a {@link Graph} * @author Martin Steiger */ public class TriangleLookup { private static final Logger logger = LoggerFactory.getLogger(TriangleLookup.class); private final BufferedImage image; private final DataBufferInt dataBuffer; // TODO: consider not storing this explicitly -> O(1) -> O(log n) // due to binary search in region-triangle start index list private final List<Triangle> triangles; private final Rect2i bounds; /** * Creates a lookup image for the graph's region triangles */ public TriangleLookup(Graph graph) { bounds = graph.getBounds(); // TODO: maybe use USHORT_GRAY instead image = new BufferedImage(bounds.width(), bounds.height(), BufferedImage.TYPE_INT_RGB); Graphics2D g = image.createGraphics(); g.translate(-bounds.minX(), -bounds.minY()); try { Stopwatch sw = Stopwatch.createStarted(); triangles = drawTriangles(g, graph); logger.debug("Cached {} triangle lookups in {}ms.", triangles.size(), sw.elapsed(TimeUnit.MILLISECONDS)); } finally { g.dispose(); } dataBuffer = (DataBufferInt) image.getRaster().getDataBuffer(); } /** * @param x the x world coord. * @param y the y world coord. * @return the triangle that contains the point or <code>null</code> */ public Triangle findTriangleAt(int x, int y) { int imgX = x - bounds.minX(); int imgY = y - bounds.minY(); if (imgX < 0 || imgY < 0 || imgX >= image.getWidth() || imgY >= image.getHeight()) { logger.warn("Coordinate {}/{} is out of bounds", x, y); return null; } // index 0 is reserved for missing coverage // we need to subtract 1 to get the real list index int index1 = dataBuffer.getElem(imgY * image.getWidth() + imgX) & 0xFFFFFF; if (index1 < 1 || index1 > triangles.size()) { logger.warn("Could not find a triangle for {}/{}", x, y); return null; } return triangles.get(index1 - 1); } private static List<Triangle> drawTriangles(Graphics2D g, Graph graph) { List<Region> regions = graph.getRegions(); List<Triangle> triangles = Lists.newArrayList(); // index 0 is reserved for missing coverage int index = 1; for (final Region reg : regions) { for (Triangle tri : reg.computeTriangles()) { BaseVector2f p0 = tri.getRegion().getCenter(); BaseVector2f p1 = tri.getCorner1().getLocation(); BaseVector2f p2 = tri.getCorner2().getLocation(); Path2D path = new Path2D.Double(); path.moveTo(p0.getX(), p0.getY()); path.lineTo(p1.getX(), p1.getY()); path.lineTo(p2.getX(), p2.getY()); triangles.add(tri); g.setColor(new Color(index++)); g.fill(path); } } return triangles; } /** * @return */ public Rect2i getBounds() { return bounds; } }