Android Open Source - flingbox Polygon Utils






From Project

Back to project page flingbox.

License

The source code is released under:

GNU General Public License

If you think the Android project flingbox listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/*
 *  Flingbox - An OpenSource physics sandbox for Google's Android
 *  Copyright (C) 2009  Jon Ander Pealba & Endika Gutirrez
 */*from   ww w . j av  a  2  s.  c  o  m*/
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package edu.eside.flingbox.math;

import java.util.ArrayList;

/**
 * Implements some utilities for polygons.
 */
public final class PolygonUtils {
  /**
   * Prevent instance creation
   */
  private PolygonUtils() { }
  
  /**
   * The Douglas-Peucker algorithm is an algorithm for reducing the number 
   * of points in a curve that is approximated by a series of points.
   * The end of this function is a good moment to call the GarbageCollector
   * 
   * @param points  Array of the polygon's points 
   * @param epsilon  Max distance to ignore a point
   * @return      New array with optimized points
   */
  public static Vector2D[] douglasPeuckerReducer(final Vector2D[] points, final float epsilon) {
    final int lastPoint = points.length -1;
    if (lastPoint < 3 || epsilon <= 0.0f)
      return points;  // No reduction possible
    
    final ArrayList<Vector2D> reducedPolygon = new ArrayList<Vector2D>();
    
    reducedPolygon.add(points[0]);  // First point will not be include
    
    /* Call recursively to algorithm */
    douglasPeucker(points, epsilon, 0, lastPoint, reducedPolygon);
    
    if (points[0].distanceToPoint(points[lastPoint]) > epsilon)
      reducedPolygon.add(points[lastPoint]); // Last point neither
    
    reducedPolygon.trimToSize();

    return (Vector2D[]) reducedPolygon.toArray(new Vector2D[0]);
  }
  
  /**
   * Recursively Calculation of DouglasPeucker Algorithm
   */
  private static void douglasPeucker(final Vector2D[] points, final float epsilon, 
      final int first, final int last, final ArrayList<Vector2D> resultPoints) {
    
    float maxDistance = 0.0f;
    int maxDistanceIndex = 0;
    
    /* Find maximum distance point.  */
    for (int i = first + 1; i < last ; i++) {
      float distance = distanceFromLineToPoint(points[first], points[last], points[i]);
      if (distance > maxDistance) {  // Store point
        maxDistance = distance;
        maxDistanceIndex = i;
      }
    }
    
    /* If point distance is more than epsilon then split points array in 
     * two parts and iterate for each. 
     */
    if (maxDistance > epsilon) {
      /* Find in previous segment */
      if ((maxDistanceIndex - first) > 1)
        douglasPeucker(points, epsilon, first, maxDistanceIndex, resultPoints);
      /* Put point in buffer(2 coords) */
      resultPoints.add(points[maxDistanceIndex]);  
      /* Continue searching important points */
      if ((last - maxDistanceIndex) > 1)
        douglasPeucker(points, epsilon, maxDistanceIndex, last, resultPoints);
    }
  }  
  
  /**
   * Computes the triangulation of a polygon(tesellation) with ear-clipping 
   * algorithm. 
   * @param Vector2Ds  Array of polygon's points
   * @return      Will return n-2 group of 3 points, for n sides polygon
   *           or null if not enough points
   */
  public static short[] triangulatePolygon(final Vector2D[] Vector2Ds) {
    final int Vector2DsCount = Vector2Ds.length;
    if (Vector2DsCount < 3)
      return null;
    
    // n-2 group of 3 Vector2Ds, for n sides polygon 
    short[] triangles = new short[3 * (Vector2DsCount - 2)];
    boolean[] included = new boolean[Vector2DsCount];

    int topVector2DIndex;
    float topVector2D;
    for (int trianglesCount = 0; trianglesCount < (Vector2DsCount - 3); ++trianglesCount) {
      topVector2DIndex = 0;
      topVector2D = Float.NEGATIVE_INFINITY;
      
      // Find top Vector2D to find triangle
      for (int i = 0; i < Vector2DsCount; i++) {
        // Find top Vector2D
        if (!included[i] && (Vector2Ds[i].i > topVector2D)) {
          topVector2D = Vector2Ds[i].i;
          topVector2DIndex = i;
        }
      }
      
      // Exclude Vector2D for next iteration
      included[topVector2DIndex] = true;
      
      // Save triangle
      int prevVector2D = topVector2DIndex; // Find previous Vector2D
      do {
        if (--prevVector2D < 0)
          prevVector2D = Vector2DsCount - 1;
      } while (included[prevVector2D]);
      
      int nextVector2D = topVector2DIndex; // Find next Vector2D
      do {
        if (++nextVector2D >= Vector2DsCount)
          nextVector2D = 0;
      } while (included[nextVector2D]);
      
      // Store triangle
      triangles[trianglesCount * 3] = (short)prevVector2D;  // Store into array
      triangles[trianglesCount * 3 + 1] = (short)topVector2DIndex;
      triangles[trianglesCount * 3 + 2] = (short)nextVector2D;
    }

    return triangles;
  }
  
  /**
   * Checks if a Vector2D is contained by a polygon.
   * It's based on Winding number algorithm.
   * More info at {@link http://en.wikipedia.org/wiki/Winding_number}
   * 
   * @param polygon polygon's Vector2Ds
   * @param Vector2D Vector2D to be checked
   */
  public static boolean polygonConatinsPoint(Vector2D[] polygon, Vector2D Vector2D) {
    final int Vector2DsCount = polygon.length;
    final float px = Vector2D.i, py = Vector2D.j;
    int c = 0;
    for (int i = 0; i < Vector2DsCount; i++) {
      Vector2D v1 = polygon[i];
      Vector2D v2 = polygon[(i + 1) % Vector2DsCount] ;
      if ((v1.j < py) && (v2.j > py)) {
        if (v1.i > px || v2.i > px)
          c++;
        // Check if Vector2D is at the left or the right side of the object
        //final float segmentAtX = ((v2.i - v1.i) / (v2.j - v1.j)) * (py - v1.j) + v1.i;
        //if (segmentAtX > px) 
        //  c++;
        //else if (segmentAtX == px)
        //  return true; // is over the bounder
      } else if ((v1.j > py) && (v2.j < py)) {
        if (v1.i > px || v2.i > px)
          c--;
        // Check if Vector2D is at the left or the right side of the object
        //final float segmentAtX = ((v2.i - v1.i) / (v2.j - v1.j)) * (py - v1.j) + v1.i;
        //if (segmentAtX > px) 
        //  c--;
        //else if (segmentAtX == px)
        //  return true; // is over the bounder
      }
    }
    return c != 0;
  }
  
  /**
   * Computes area of polygon.
   * 
   * @param Vector2Ds Polygon's Vector2Ds
   * @return Polygon's area. if Vector2Ds are counter-clockwise the 
   * result will be positive, else it'll be negative
   */
  public static float polygonArea(final Vector2D[] Vector2Ds) {
    final int lastVector2D = Vector2Ds.length - 1;
    
    float area = Vector2Ds[lastVector2D].i * Vector2Ds[0].j 
      - Vector2Ds[0].i * Vector2Ds[lastVector2D].j;
    
    Vector2D Vector2D, nextVector2D;
    for (int i = 0; i < lastVector2D; i++) {
      Vector2D = Vector2Ds[i];
      nextVector2D = Vector2Ds[i + 1];
      area += Vector2D.i * nextVector2D.j - nextVector2D.i * Vector2D.j;
    }
    return area / 2f;
  }
  
  /**
   * Computes the polygon's centroid
   * 
   * @param Vector2Ds Polygon's Vector2Ds
   * @return centroid 
   */
  public static Vector2D polygonCentroid(final Vector2D[] contour) {
    final int pointsCount = contour.length;
    float cx = 0f, cy = 0f;
    
    for (int i = 0; i < pointsCount; i++) {
      float p0x = contour[i].i, p1x = contour[(i + 1) % pointsCount].i;
      float p0y = contour[i].j, p1y = contour[(i + 1) % pointsCount].j;
      final float k = (p0x * p1y - p1x * p0y);
      cx += (p0x + p1x) * k;
      cy += (p0y + p1y) * k;
    }
    final float d = 6f * polygonArea(contour);
    cx /= d;
    cy /= d;

    return new Vector2D(cx, cy);
  }
  
  
  /**
   * Computes the polygon's normals.  
   * 
   * @param contour Counterclockwise polygon points
   * @return Polygon's normals
   */
  public static Vector2D[] computePolygonNormals(final Vector2D[] contour) {
    final int pointsCount = contour.length;
    Vector2D[] normals = new Vector2D[pointsCount];
    
    for (int i = 0; i < pointsCount; i++) {
      final Vector2D p0 = contour[i], p1 = contour[i == pointsCount - 1 ? 0 : i ]; 
      normals[i] = new Vector2D((p1.j - p0.j), (p0.i - p1.i));//.normalize();
    }
    
    return normals;
  }
  
  /**
   * Computes minimum distance from line to point
   */
  public static float distanceFromLineToPoint(final Vector2D p0, final Vector2D p1, final Vector2D p) {
    final float area = (p0.i * p1.j + p1.i * p.j + p.i * p0.j 
          - p1.i * p0.j - p.i * p1.j - p0.i * p.j) / 2f;
    final float base = (float) Math.sqrt((p1.i - p0.i) * (p1.i - p0.i) 
          + (p1.j - p0.j) * (p1.j - p0.j));
    return (float) Math.abs(2f * area / base);
  }
  
}




Java Source Code List

edu.eside.flingbox.BodySettingsDialog.java
edu.eside.flingbox.FlingboxActivity.java
edu.eside.flingbox.PreferencesActivity.java
edu.eside.flingbox.Preferences.java
edu.eside.flingbox.bodies.Body.java
edu.eside.flingbox.bodies.Polygon.java
edu.eside.flingbox.graphics.RenderBody.java
edu.eside.flingbox.graphics.RenderCamera.java
edu.eside.flingbox.graphics.RenderPolygon.java
edu.eside.flingbox.graphics.SceneRenderer.java
edu.eside.flingbox.input.SceneGestureDetector.java
edu.eside.flingbox.math.Intersect.java
edu.eside.flingbox.math.Matrix22.java
edu.eside.flingbox.math.PolygonUtils.java
edu.eside.flingbox.math.Vector2D.java
edu.eside.flingbox.physics.PhysicAtomicBody.java
edu.eside.flingbox.physics.PhysicBody.java
edu.eside.flingbox.physics.PhysicPolygon.java
edu.eside.flingbox.physics.ScenePhysics.java
edu.eside.flingbox.physics.collisions.Arbiter.java
edu.eside.flingbox.physics.collisions.ColliderPolygon.java
edu.eside.flingbox.physics.collisions.Collider.java
edu.eside.flingbox.physics.collisions.ContactSolver.java
edu.eside.flingbox.physics.collisions.Contact.java
edu.eside.flingbox.physics.gravity.GravitySource.java
edu.eside.flingbox.scene.DrawingBody.java
edu.eside.flingbox.scene.DrawingPolygon.java
edu.eside.flingbox.scene.Scene.java
edu.eside.flingbox.utils.PositionComparator.java
edu.eside.flingbox.xml.InvalidXmlException.java
edu.eside.flingbox.xml.XmlExporter.java
edu.eside.flingbox.xml.XmlImporter.java