/**
   * Sets polygon with repeating texture region, the size of repeating grid is equal to region size
   *
   * @param region - region to repeat
   * @param vertices - cw vertices of polygon
   * @param density - number of regions per polygon width bound
   */
  public void setPolygon(TextureRegion region, float[] vertices, float density) {

    this.region = region;

    vertices = offset(vertices);

    Polygon polygon = new Polygon(vertices);
    Polygon tmpPoly = new Polygon();
    Polygon intersectionPoly = new Polygon();
    EarClippingTriangulator triangulator = new EarClippingTriangulator();

    int idx;

    Rectangle boundRect = polygon.getBoundingRectangle();

    if (density == -1) density = boundRect.getWidth() / region.getRegionWidth();

    float regionAspectRatio = (float) region.getRegionHeight() / (float) region.getRegionWidth();
    cols = (int) (Math.ceil(density));
    gridWidth = boundRect.getWidth() / density;
    gridHeight = regionAspectRatio * gridWidth;
    rows = (int) Math.ceil(boundRect.getHeight() / gridHeight);

    for (int col = 0; col < cols; col++) {
      for (int row = 0; row < rows; row++) {
        float[] verts = new float[8];
        idx = 0;
        verts[idx++] = col * gridWidth;
        verts[idx++] = row * gridHeight;
        verts[idx++] = (col) * gridWidth;
        verts[idx++] = (row + 1) * gridHeight;
        verts[idx++] = (col + 1) * gridWidth;
        verts[idx++] = (row + 1) * gridHeight;
        verts[idx++] = (col + 1) * gridWidth;
        verts[idx] = (row) * gridHeight;
        tmpPoly.setVertices(verts);

        Intersector.intersectPolygons(polygon, tmpPoly, intersectionPoly);
        verts = intersectionPoly.getVertices();
        if (verts.length > 0) {
          parts.add(snapToGrid(verts));
          ShortArray arr = triangulator.computeTriangles(verts);
          indices.add(arr.toArray());
        } else {
          // adding null for key consistancy, needed to get col/row from key
          // the other alternative is to make parts - IntMap<FloatArray>
          parts.add(null);
        }
      }
    }

    buildVertices();
  }
 /**
  * Loads a PolygonRegion from a PSH (Polygon SHape) file. The PSH file format defines the polygon
  * vertices before triangulation:
  *
  * <p>s 200.0, 100.0, ...
  *
  * <p>Lines not prefixed with "s" are ignored. PSH files can be created with external tools, eg:
  * <br>
  * https://code.google.com/p/libgdx-polygoneditor/ <br>
  * http://www.codeandweb.com/physicseditor/
  *
  * @param file file handle to the shape definition file
  */
 public PolygonRegion load(TextureRegion textureRegion, FileHandle file) {
   BufferedReader reader = file.reader(256);
   try {
     while (true) {
       String line = reader.readLine();
       if (line == null) break;
       if (line.startsWith("s")) {
         // Read shape.
         String[] polygonStrings = line.substring(1).trim().split(",");
         float[] vertices = new float[polygonStrings.length];
         for (int i = 0, n = vertices.length; i < n; i++)
           vertices[i] = Float.parseFloat(polygonStrings[i]);
         // It would probably be better if PSH stored the vertices and triangles, then we don't
         // have to triangulate here.
         return new PolygonRegion(
             textureRegion, vertices, triangulator.computeTriangles(vertices).toArray());
       }
     }
   } catch (IOException ex) {
     throw new GdxRuntimeException("Error reading polygon shape file: " + file, ex);
   } finally {
     StreamUtils.closeQuietly(reader);
   }
   throw new GdxRuntimeException("Polygon shape not found: " + file);
 }
  /**
   * Creates an array of PolySpatials based on fixture information from the scene. Note that
   * fixtures create aligned textures.
   *
   * @param scene
   */
  private void createPolySpatialsFromRubeFixtures(RubeScene scene) {
    Array<Body> bodies = scene.getBodies();

    EarClippingTriangulator ect = new EarClippingTriangulator();

    if ((bodies != null) && (bodies.size > 0)) {
      polySpatials = new Array<PolySpatial>();
      Vector2 bodyPos = new Vector2();
      // for each body in the scene...
      for (int i = 0; i < bodies.size; i++) {
        Body body = bodies.get(i);
        bodyPos.set(body.getPosition());

        Array<Fixture> fixtures = body.getFixtureList();

        if ((fixtures != null) && (fixtures.size > 0)) {
          // for each fixture on the body...
          for (int j = 0; j < fixtures.size; j++) {
            Fixture fixture = fixtures.get(j);

            String textureName = (String) scene.getCustom(fixture, "TextureMask", null);
            if (textureName != null) {
              String textureFileName = "data/" + textureName;
              Texture texture = textureMap.get(textureFileName);
              TextureRegion textureRegion = null;
              if (texture == null) {
                texture = new Texture(textureFileName);
                texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
                textureMap.put(textureFileName, texture);
                textureRegion = new TextureRegion(texture);
                textureRegionMap.put(texture, textureRegion);
              } else {
                textureRegion = textureRegionMap.get(texture);
              }

              // only handle polygons at this point -- no chain, edge, or circle fixtures.
              if (fixture.getType() == Shape.Type.Polygon) {
                PolygonShape shape = (PolygonShape) fixture.getShape();
                int vertexCount = shape.getVertexCount();
                float[] vertices = new float[vertexCount * 2];

                // static bodies are texture aligned and do not get drawn based off of the related
                // body.
                if (body.getType() == BodyType.StaticBody) {
                  for (int k = 0; k < vertexCount; k++) {

                    shape.getVertex(k, mTmp);
                    mTmp.rotate(body.getAngle() * MathUtils.radiansToDegrees);
                    mTmp.add(
                        bodyPos); // convert local coordinates to world coordinates to that textures
                                  // are
                    // aligned
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }

                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, Color.WHITE);
                  polySpatials.add(spatial);
                } else {
                  // all other fixtures are aligned based on their associated body.
                  for (int k = 0; k < vertexCount; k++) {
                    shape.getVertex(k, mTmp);
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }
                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, body, Color.WHITE);
                  polySpatials.add(spatial);
                }
              } else if (fixture.getType() == Shape.Type.Circle) {
                CircleShape shape = (CircleShape) fixture.getShape();
                float radius = shape.getRadius();
                int vertexCount = (int) (12f * radius);
                float[] vertices = new float[vertexCount * 2];
                System.out.println("SpatialFactory: radius: " + radius);
                if (body.getType() == BodyType.StaticBody) {
                  mTmp3.set(shape.getPosition());
                  for (int k = 0; k < vertexCount; k++) {
                    // set the initial position
                    mTmp.set(radius, 0);
                    // rotate it by 1/vertexCount * k
                    mTmp.rotate(360f * k / vertexCount);
                    // add it to the position.
                    mTmp.rotate(body.getAngle() * MathUtils.radiansToDegrees);
                    mTmp.add(mTmp3);
                    mTmp.add(
                        bodyPos); // convert local coordinates to world coordinates to that textures
                                  // are aligned
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }
                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, Color.WHITE);
                  polySpatials.add(spatial);
                } else {
                  mTmp3.set(shape.getPosition());
                  for (int k = 0; k < vertexCount; k++) {
                    // set the initial position
                    mTmp.set(radius, 0);
                    // rotate it by 1/vertexCount * k
                    mTmp.rotate(360f * k / vertexCount);
                    // add it to the position.
                    mTmp.add(mTmp3);
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }
                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, body, Color.WHITE);
                  polySpatials.add(spatial);
                }
              }
            }
          }
        }
      }
    }
  }