Package org.newdawn.slick.tests

Source Code of org.newdawn.slick.tests.GeomUtilTileTest

package org.newdawn.slick.tests;

import java.util.ArrayList;
import java.util.HashSet;

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.geom.Circle;
import org.newdawn.slick.geom.GeomUtil;
import org.newdawn.slick.geom.GeomUtilListener;
import org.newdawn.slick.geom.Polygon;
import org.newdawn.slick.geom.Shape;
import org.newdawn.slick.geom.Vector2f;

/**
* A test to try shape building from multiple tiles
*
* @author Kevin Glass
*/
public class GeomUtilTileTest extends BasicGame implements GeomUtilListener {
  /** The shape we're cutting out of */
  private Shape source;
  /** The shape we're cutting */
  private Shape cut;
  /** The resulting shape */
  private Shape[] result;

  /** The util under test */
  private GeomUtil util = new GeomUtil();

  /** The original list of shapes */
  private ArrayList original = new ArrayList();
  /** The original list of shapes */
  private ArrayList combined = new ArrayList();

  /** The list of intersection points */
  private ArrayList intersections = new ArrayList();
  /** The list of used points */
  private ArrayList used = new ArrayList();

  /** The quad space of shapes that need to be checked against each other */
  private ArrayList[][] quadSpace;
  /** The shapes present in each quad space - used to optimize generation */
  private Shape[][] quadSpaceShapes;
 
  /**
   * Create a simple test
   */
  public GeomUtilTileTest() {
    super("GeomUtilTileTest");
  }

  /**
   * So this is going to generate a quad space that holds that segments the
   * shapes into quads across the map. This makes it tunable and limits the number
   * of comparisons that need to be done for each shape
   *
   * @param shapes The shapes to be segments
   * @param minx The minimum x value of the map
   * @param miny The mimimum y value of the map
   * @param maxx The maximum x value of the map
   * @param maxy The maximum y value of the map
   * @param segments The number of segments to split the map into
   */
  private void generateSpace(ArrayList shapes, float minx, float miny, float maxx, float maxy, int segments) {
    quadSpace = new ArrayList[segments][segments];
    quadSpaceShapes = new Shape[segments][segments];
   
    float dx = (maxx - minx) / segments;
    float dy = (maxy - miny) / segments;
   
    for (int x=0;x<segments;x++) {
      for (int y=0;y<segments;y++) {
        quadSpace[x][y] = new ArrayList();
       
        // quad for this segment
        Polygon segmentPolygon = new Polygon();
        segmentPolygon.addPoint(minx+(dx*x), miny+(dy*y));
        segmentPolygon.addPoint(minx+(dx*x)+dx, miny+(dy*y));
        segmentPolygon.addPoint(minx+(dx*x)+dx, miny+(dy*y)+dy);
        segmentPolygon.addPoint(minx+(dx*x), miny+(dy*y)+dy);
       
        for (int i=0;i<shapes.size();i++) {
          Shape shape = (Shape) shapes.get(i);
         
          if (collides(shape, segmentPolygon)) {
            quadSpace[x][y].add(shape);
          }
        }
       
        quadSpaceShapes[x][y] = segmentPolygon;
      }
    }
  }
 
  /**
   * Remove the given shape from the quad space
   *
   * @param shape The shape to remove
   */
  private void removeFromQuadSpace(Shape shape) {
    int segments = quadSpace.length;
   
    for (int x=0;x<segments;x++) {
      for (int y=0;y<segments;y++) {
        quadSpace[x][y].remove(shape);
      }
    }
  }
 
  /**
   * Add a particular shape to quad space
   *
   * @param shape The shape to be added
   */
  private void addToQuadSpace(Shape shape) {
    int segments = quadSpace.length;
   
    for (int x=0;x<segments;x++) {
      for (int y=0;y<segments;y++) {
        if (collides(shape, quadSpaceShapes[x][y])) {
          quadSpace[x][y].add(shape);
        }
      }
    }
  }
 
  /**
   * Perform the cut
   */
  public void init() {
    int size = 10;
    int[][] map = new int[][] {
        { 0, 0, 0, 0, 0, 0, 0, 3, 0, 0 },
        { 0, 1, 1, 1, 0, 0, 1, 1, 1, 0 },
        { 0, 1, 1, 0, 0, 0, 5, 1, 6, 0 },
        { 0, 1, 2, 0, 0, 0, 4, 1, 1, 0 },
        { 0, 1, 1, 0, 0, 0, 1, 1, 0, 0 },
        { 0, 0, 0, 0, 3, 0, 1, 1, 0, 0 },
        { 0, 0, 0, 1, 1, 0, 0, 0, 1, 0 },
        { 0, 0, 0, 1, 1, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
        };
   
//    size = 100;
//    map = new int[size][size];
//    for (int x=0;x<size;x++) {
//      for (int y=0;y<size;y++) {
//        if ((x+y) % 2 == 0) {
//          map[y][x] = 1;
//        }
//      }
//    }
   
    for (int x = 0; x < map[0].length; x++) {
      for (int y = 0; y < map.length; y++) {
        if (map[y][x] != 0) {
          switch (map[y][x]) {
          case 1:
            Polygon p2 = new Polygon();
            p2.addPoint(x * 32, y * 32);
            p2.addPoint((x * 32) + 32, y * 32);
            p2.addPoint((x * 32) + 32, (y * 32) + 32);
            p2.addPoint(x * 32, (y * 32) + 32);
            original.add(p2);
            break;
          case 2:
            Polygon poly = new Polygon();
            poly.addPoint(x * 32, y * 32);
            poly.addPoint((x * 32) + 32, y * 32);
            poly.addPoint(x * 32, (y * 32) + 32);
            original.add(poly);
            break;
          case 3:
            Circle ellipse = new Circle((x*32)+16,(y*32)+32,16,16);
            original.add(ellipse);
            break;
          case 4:
            Polygon p = new Polygon();
            p.addPoint((x * 32) + 32, (y * 32));
            p.addPoint((x * 32) + 32, (y * 32)+32);
            p.addPoint(x * 32, (y * 32) + 32);
            original.add(p);
            break;
          case 5:
            Polygon p3 = new Polygon();
            p3.addPoint((x * 32), (y * 32));
            p3.addPoint((x * 32) + 32, (y * 32));
            p3.addPoint((x * 32) + 32, (y * 32)+32);
            original.add(p3);
            break;
          case 6:
            Polygon p4 = new Polygon();
            p4.addPoint((x * 32), (y * 32));
            p4.addPoint((x * 32) + 32, (y * 32));
            p4.addPoint((x * 32), (y * 32)+32);
            original.add(p4);
            break;
          }
        }
      }
    }

    long before = System.currentTimeMillis();
   
    // the quad spaced method
    generateSpace(original, 0, 0, (size+1)*32,(size+1)*32,8);
    combined = combineQuadSpace();
   
    // the brute force method
    //combined = combine(original);
   
    long after = System.currentTimeMillis();
    System.out.println("Combine took: "+(after-before));
    System.out.println("Combine result: "+combined.size());
  }

  /**
   * Combine the shapes in the quad space
   * 
   * @return The newly combined list of shapes
   */
  private ArrayList combineQuadSpace() {
    boolean updated = true;
    while (updated) {
      updated = false;
     
      for (int x=0;x<quadSpace.length;x++) {
        for (int y=0;y<quadSpace.length;y++) {
          ArrayList shapes = quadSpace[x][y];
          int before = shapes.size();
          combine(shapes);
          int after = shapes.size();
         
          updated |= before != after;
        }
      }
    }
   
    // at this stage all the shapes that can be combined within their quads
    // will have gone on - we may need to combine stuff on the boundary tho
    HashSet result = new HashSet();
   
    for (int x=0;x<quadSpace.length;x++) {
      for (int y=0;y<quadSpace.length;y++) {
        result.addAll(quadSpace[x][y]);
      }
    }
   
    return new ArrayList(result);
  }
 
  /**
   * Combine a set of shapes together
   *
   * @param shapes
   *            The shapes to be combined
   * @return The list of combined shapes
   */
  private ArrayList combine(ArrayList shapes) {
    ArrayList last = shapes;
    ArrayList current = shapes;
    boolean first = true;

    while ((current.size() != last.size()) || (first)) {
      first = false;
      last = current;
      current = combineImpl(current);
    }

    ArrayList pruned = new ArrayList();
    for (int i = 0; i < current.size(); i++) {
      pruned.add(((Shape) current.get(i)).prune());
    }
    return pruned;
  }

  /**
   * Attempt to find a simple combination that can be performed
   *
   * @param shapes
   *            The shapes to be combined
   * @return The new list of shapes - this will be the same length as the
   *         input if there are no new combinations
   */
  private ArrayList combineImpl(ArrayList shapes) {
    ArrayList result = new ArrayList(shapes);
    if (quadSpace != null) {
      result = shapes;
    }
   
    for (int i = 0; i < shapes.size(); i++) {
      Shape first = (Shape) shapes.get(i);
      for (int j = i + 1; j < shapes.size(); j++) {
        Shape second = (Shape) shapes.get(j);

        if (!first.intersects(second)) {
          continue;
        }
       
        Shape[] joined = util.union(first, second);
        if (joined.length == 1) {
          if (quadSpace != null) {
            removeFromQuadSpace(first);
            removeFromQuadSpace(second);
            addToQuadSpace(joined[0]);
          } else {
            result.remove(first);
            result.remove(second);
            result.add(joined[0]);
          }
          return result;
        }
      }
    }

    return result;
  }

  /**
   * Check if two shapes collide
   *
   * @param shape1 The first shape
   * @param shape2 The second shape
   * @return True if the shapes collide (i.e. intersection or overlap)
   */
  public boolean collides(Shape shape1, Shape shape2) {
    if (shape1.intersects(shape2)) {
      return true;
    }
    for (int i=0;i<shape1.getPointCount();i++) {
      float[] pt = shape1.getPoint(i);
      if (shape2.contains(pt[0], pt[1])) {
        return true;
      }
    }
    for (int i=0;i<shape2.getPointCount();i++) {
      float[] pt = shape2.getPoint(i);
      if (shape1.contains(pt[0], pt[1])) {
        return true;
      }
    }
   
    return false;
  }
 
  /**
   * @see BasicGame#init(GameContainer)
   */
  public void init(GameContainer container) throws SlickException {
    util.setListener(this);
    init();
    //container.setVSync(true);
  }

  /**
   * @see BasicGame#update(GameContainer, int)
   */
  public void update(GameContainer container, int delta)
      throws SlickException {
  }

  /**
   * @see org.newdawn.slick.Game#render(GameContainer, Graphics)
   */
  public void render(GameContainer container, Graphics g)
      throws SlickException {
    g.setColor(Color.green);
    for (int i = 0; i < original.size(); i++) {
      Shape shape = (Shape) original.get(i);
      g.draw(shape);
    }

    g.setColor(Color.white);
    if (quadSpaceShapes != null) {
      g.draw(quadSpaceShapes[0][0]);
    }
   
    g.translate(0, 320);

    for (int i = 0; i < combined.size(); i++) {
      g.setColor(Color.white);
      Shape shape = (Shape) combined.get(i);
      g.draw(shape);
      for (int j = 0; j < shape.getPointCount(); j++) {
        g.setColor(Color.yellow);
        float[] pt = shape.getPoint(j);
        g.fillOval(pt[0] - 1, pt[1] - 1, 3, 3);
      }
    }

  }

  /**
   * Entry point to our test
   *
   * @param argv
   *            The arguments passed to the test
   */
  public static void main(String[] argv) {
    try {
      AppGameContainer container = new AppGameContainer(
          new GeomUtilTileTest());
      container.setDisplayMode(800, 600, false);
      container.start();
    } catch (SlickException e) {
      e.printStackTrace();
    }
  }

  public void pointExcluded(float x, float y) {
  }

  public void pointIntersected(float x, float y) {
    intersections.add(new Vector2f(x, y));
  }

  public void pointUsed(float x, float y) {
    used.add(new Vector2f(x, y));
  }
}
TOP

Related Classes of org.newdawn.slick.tests.GeomUtilTileTest

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.