Package hermes.hshape

Source Code of hermes.hshape.HCircle

package hermes.hshape;

import hermes.Hermes;
import processing.core.PVector;
import static hermes.HermesMath.*;

/**
* Represents a circle.
*/
public class HCircle extends HShape {

  private PVector _center;
  private float _radius;
 
  /**
   * Constructor defining center of circle
   * as position of object.
   * @param position
   * @param radius
   */
  public HCircle(PVector position, float radius) {
    super(position);
   
    assert radius >= 0 : "In HCircle constructor, radius must be positive"; //TODO can radius be 0?
   
    _center = new PVector(0,0);
    _radius = radius;
  }
 
  /**
   * Constructor defining center of circle
   * to be a certain distance away from the position.
   * @param position
   * @param center
   * @param radius
   */
  public HCircle(PVector position, PVector center, float radius) {
    super(position);
   
    assert center != null : "In HCircle constructor, center must be a valid PVector";
    assert radius >= 0 : "In HCircle constructor, radius must be non-negative"; //TODO can radius be 0?
   
    _center = center;
    _radius = radius;
  }
 
  /**
   * Getter for center
   */
  public PVector getCenter() {
    return _center;
  }
 
  /**
   * Getter for radius
   */
  public float getRadius() {
    return _radius;
  }
 
  @Override
  public boolean contains(PVector point) {
      float distX = point.x - _position.x;
      float distY = point.y - _position.y;
      return distX*distX + distY*distY <= _radius*_radius;
  }
 
  @Override
  public boolean contains(float x, float y) {
      float distX = x - _position.x;
      float distY = y - _position.y;
      return distX*distX + distY*distY <= _radius*_radius;
  }
 
  @Override
  public PVector projectionVector(HShape other) {
    assert other != null : "HCircle.collide: other must be a validHShape";
    PVector opposite = other.projectionVector(this);
    return opposite == null ? null : reverse(opposite);
  }

  @Override
  public PVector projectionVector(HPolygon other) {
    PVector opposite = other.projectionVector(this);
    return opposite == null ? null : reverse(opposite);
  }
 
  @Override
  public PVector projectionVector(HCircle other) {
    //Get the center of this circle
    PVector worldCenterThis = PVector.add(_position, _center);
    //Get the center of the other circle
    PVector worldCenterOther = PVector.add(other.getPosition(), other.getCenter());
   
    //HCircles are colliding if distance between them is less than sum of radii
    PVector dir = PVector.sub(worldCenterOther, worldCenterThis);
    float distance = dir.mag();
    float sumRadii = _radius + other._radius;
    boolean collides = distance <= sumRadii;
   
    //Projection vector is the unit vector pointing from this circle to other scaled by overlap
    if(collides) {
      float magnitude = sumRadii - distance;
      dir.normalize();
      dir.mult(magnitude);
      return dir;
    }
    else return null;
  }
 
  @Override
  public PVector projectionVector(HRectangle other) {
    //Get the center of this circle
    PVector worldCenter = PVector.add(_center, _position);
    //Figure out what voronoi region of the rectangle the circle is in
    PVector min = PVector.add(other._position, other.getMin());
    PVector max = PVector.add(other._position, other.getMax());
    if(min.x <= worldCenter.x) {
      if(worldCenter.x <= max.x) {
        //In regions above or below rectangle,
        //compare y projections
        float minProject = worldCenter.y - _radius;
        float maxProject = worldCenter.y + _radius;
        if(min.y <= maxProject && minProject <= max.y) {
          float topCollide = max.y - minProject;
          float bottomCollide = maxProject - min.y;
          return (topCollide >= bottomCollide ?
              new PVector(0,bottomCollide):
              new PVector(0,-topCollide));
         
        }
      }
      else if(min.y <= worldCenter.y) {
        if(worldCenter.y <= max.y) {
          //In region directly to right of rectangle
          //Compare x projections
          float minProject = worldCenter.x - _radius;
          if(minProject <= max.x) {
            return new PVector(minProject - max.x,0);
          }
        }
        else {
          //In region to the right&up of rectangle
          //Get projection of both along up-right vertex (max)
          return getOverlap(worldCenter,max);
        }
      }
      else {
        //In region to the right&down of rectangle
        //Get projection of both along bottom-right vertex
        PVector brVertex = new PVector(max.x, min.y);
        return getOverlap(worldCenter, brVertex);
      }
    }
    else if(min.y <= worldCenter.y) {
      if(worldCenter.y <= max.y) {
        //In region directly to the left of rectangle
        //Compare x projections
        float maxProject = worldCenter.x + _radius;
        if(min.x <= maxProject) {
          return new PVector(maxProject - min.x,0);
        }
      }
      else {
        //In region to the left&up of rectangle
        //Get projection of both along top-left vertex
        PVector tlVertex = new PVector(min.x, max.y);
        return getOverlap(worldCenter, tlVertex);
      }
    }
    else {
      //In region to the left&down of rectangle
      //Get projection of both along bottom-left vertex (min)
      return getOverlap(worldCenter, min);
    }
   
    return null;
  }
 
  /**
   * Helper method.
   * Finds overlap between a circle and the corner of a rectangle.
   * @param worldCenter
   * @param vertex
   * @return projection vector when colliding, null when not
   */
  private PVector getOverlap(PVector worldCenter, PVector vertex) {
    //Get vector from circle to vertex and overlap of shapes
    PVector axis = PVector.sub(vertex, worldCenter);
    float overlap = _radius - axis.mag();
    if(overlap >= 0) {
      //Get projection vector
      axis.normalize();
      axis.mult(overlap);
      return axis;
    }
    else return null;
  }
 
  @Override
  public HRectangle getBoundingBox() {
    return new HRectangle(PVector.sub(PVector.add(_position, _center),new PVector(_radius,_radius)), 2*_radius, 2*_radius);
  }
 
  @Override
  public void draw() {
    Hermes.getPApplet().ellipse(_center.x, _center.y, 2*_radius, 2*_radius);
  }
 
  @Override
  public String toString() {
    return "Position:" + _position + "\nCenter:" + _center + "\nRadius:" + _radius;
  }

}
TOP

Related Classes of hermes.hshape.HCircle

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.