AABBテスト用コード①

参考図書

ゲームプログラミングのためのリアルタイム衝突判定 単行本 – 2005/11/1
Christer Ericson (著), 中村 達也 (翻訳)

表示まで

main


import java.util.Collections;
import java.util.Comparator;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;
import java.util.Stack;
import java.util.Arrays;
import processing.svg.*;

import java.util.List;
import java.util.Collection;
import java.util.stream.Collectors;

import processing.opengl.*;

void setup()
{
  size(500,500);
  background(255);
    
  var o1 = new Object2D();
  var o2 = new Object2D();
  var o3 = new Object2D();
  this.Objects.add(o1);
  this.Objects.add(o2);
  this.Objects.add(o3);
}

void draw()
{
  background(255);    
  noFill();
  strokeWeight(1);  
  
  for(var obj : this.Objects)
  {
    if(obj instanceof IDrawable)
    {
      ((IDrawable)obj).draw();
    }
  }
}

//全てのオブジェクト。このリストはGUI機能を持つオブジェクトを含むことがある。
List<IObject> Objects = new ArrayList<IObject>();
IObject CurrentObject = null;

class Object2D implements IObject, IDrawable
{
  IBV2D BV;
  List<PVector> coordinates = new ArrayList<PVector>();
  
  Object2D()
  {
    makeRandom(10);
    
    var aabb = createAABBMinMax2D(this.coordinates);
    this.BV = aabb;
  }
  
  void makeRandom(int count)
  {
    for(int i = 0; i<count; i++)
    {
      var v = new PVector(random(width),random(height));
      this.coordinates.add(v);
    }    
  }
  
  void draw()
  {
    drawCoords();
    drawBV();
  }
  
  void drawBV()
  {    
    IAABBMinMax2D aabbmm = (IAABBMinMax2D)this.BV;
    var ltv = aabbmm.GetLTV();
    var rbv = aabbmm.GetRBV();    
    var w = abs(rbv.x-ltv.x);
    var h = abs(rbv.y-ltv.y);    
    rect(ltv.x,ltv.y,w,h);
  }
  
  void updateBV()
  {

  }
  
  void drawCoords()
  {
    for(var v : this.coordinates)
    {
      circle(v.x,v.y,10);
    }
  }  
}


interface IObject{}

//これらにHit()を持たせるか否か
//p77
//bounding volume
interface IBV2D {}
interface IBV3D {}

interface HasBoundingVolume2D
{
  IBV2D GetBV();
}

interface HasBoundingVolume3D
{
  IBV3D GetBV();
}

interface IDrawable
{
  void draw(); 
}

interface IGUI extends IDrawable
{  
 //void draw(); 
 void draw(float x, float y);
}

interface IHit2D
{
 boolean Hit(float x, float y);
}

interface IHit3D
{
 boolean Hitfloat x, float y, float z);
}

interface ITranslate
{
 void Translate(PVector dv);
}

interface HasOrigin
{
 PVector GetOrigin();
}

interface IClickable
{
 void mousePressed();
 void mouseReleased(); 
}

interface IDraggable
{  
 void mouseDragged();  
}

AABB

コメント部分はChatGPT4(アホの時期)が提出してきたもの。


////////////////////////////////////////////////////

//axis-aligned bounding box
interface IAABBMinMax2D extends IBV2D
{
  PVector GetLTV();//left top vector
  PVector GetRBV();//right bottom vector
}

//processingの場合は2Dも3DもPVectorでまかなえる
interface IAABBMinMax3D extends IBV3D
{
  PVector GetLTV();//left top vector
  PVector GetRBV();//right bottom vector
}

interface IAABBWH2D extends IBV2D
{
  PVector GetLTV();
  float GetWidth();
  float GetHeight();
}

interface IAABBWHD3D extends IBV3D
{
  PVector GetLTV();
  float GetWidth();
  float GetHeight();
  float GetDepth();
}

//center radius
interface IAABBCR2D extends IBV2D
{
  PVector GetCV();
  float GetRX();
  float GetRY();
}

interface IAABBCR3D extends IBV3D
{
  PVector GetCV();
  float GetRX();
  float GetRY();
  float GetRZ();
}

class AABBMinMax2D implements IAABBMinMax2D {
  PVector LTV, RBV;

  AABBMinMax2D(PVector LTV, PVector RBV) {
    this.LTV = LTV;
    this.RBV = RBV;
  }
  public PVector GetLTV() { return this.LTV; }
  public PVector GetRBV() { return this.RBV; }
}

class AABBMinMax3D implements IAABBMinMax3D {
  PVector LTV, RBV;

  AABBMinMax3D(PVector LTV, PVector RBV) {
    this.LTV = LTV;
    this.RBV = RBV;
  }
  public PVector GetLTV() { return this.LTV; }
  public PVector GetRBV() { return this.RBV; }
}

class AABBWH2D implements IAABBWH2D {
  PVector LTV;
  float width, height;

  AABBWH2D(PVector LTV, float width, float height) {
    this.LTV = LTV;
    this.width = width;
    this.height = height;
  }
  public PVector GetLTV() { return this.LTV; }
  public float GetWidth() { return this.width; }
  public float GetHeight() { return this.height; }
}

class AABBWHD3D implements IAABBWHD3D {
  PVector LTV;
  float width, height, depth;

  AABBWHD3D(PVector LTV, float width, float height, float depth) {
    this.LTV = LTV;
    this.width = width;
    this.height = height;
    this.depth = depth;
  }
  public PVector GetLTV() { return this.LTV; }
  public float GetWidth() { return this.width; }
  public float GetHeight() { return this.height; }
  public float GetDepth() { return this.depth; }
}

class AABBCR2D implements IAABBCR2D {
  PVector CV;
  float rx;
  float ry;

  AABBCR2D(PVector CV, float rx, float ry) {
    this.CV = CV;
    this.rx = rx;
    this.ry = ry;
  }
  public PVector GetCV() { return this.CV; }
  public float GetRX() { return this.rx; }
  public float GetRY() { return this.ry; }
}

class AABBCR3D implements IAABBCR3D {
  PVector CV;
  float rx;
  float ry;
  float rz;

  AABBCR3D(PVector CV, float rx, float ry, float rz) {
    this.CV = CV;
    this.rx=rx;
    this.ry=ry;
    this.rz=rz;
  }
  public PVector GetCV() { return this.CV; }
  public float GetRX() { return this.rx; }
  public float GetRY() { return this.ry; }
  public float GetRZ() { return this.rz; }   
}


///////////////////////////////////////////////////////////////////////////


MinMaxIndex extremePointsAlongDirection(PVector dir, List<PVector> pt) 
{
  MinMaxIndex minmax = new MinMaxIndex(0, 0);
  float minproj = Float.MAX_VALUE;
  float maxproj = -Float.MAX_VALUE;
  
  for (int i = 0; i < pt.size(); i++) {
    // Project vector from origin to point onto direction vector
    float proj = pt.get(i).dot(dir);
    
    // Keep track of least distant point along direction vector
    if (proj < minproj) {
      minproj = proj;
      minmax.setMin(i);
    }    
    // Keep track of most distant point along direction vector
    if (proj > maxproj) {
      maxproj = proj;
      minmax.setMax(i);
    }
  }
  return minmax;
}

AABBMinMax2D createAABBMinMax2D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  return new AABBMinMax2D(new PVector(minx.x,miny.y), new PVector(maxx.x,maxy.y));
  
  //return new AABBMinMax2D(pt.get(minmaxX.getMin()), pt.get(minmaxY.getMax()));
}

AABBMinMax3D createAABBMinMax3D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
  MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  var minz = pt.get(minmaxZ.getMin());
  var maxz = pt.get(minmaxZ.getMax());
  
  return new AABBMinMax3D(new PVector(minx.x,miny.y,minz.z), new PVector(maxx.x,maxy.y,maxz.z));
  
  //return new AABBMinMax3D(pt.get(minmaxX.getMin()), pt.get(minmaxZ.getMax()));
}

AABBWH2D createAABBWH2D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  return new AABBWH2D(new PVector(minx.x,miny.y), abs(maxx.x - minx.x), abs(maxy.y - miny.y));

  //return new AABBWH2D(pt.get(minmaxX.getMin()), abs(minmaxX.getMax() - minmaxX.getMin()), abs(minmaxY.getMax() - minmaxY.getMin()));
}

AABBWHD3D createAABBWHD3D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
  MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  var minz = pt.get(minmaxZ.getMin());
  var maxz = pt.get(minmaxZ.getMax());
  return new AABBWHD3D(new PVector(minx.x, miny.y, minz.z), abs(maxx.x - minx.x), abs(maxy.y - miny.y), abs(maxz.z - minz.z));

  //return new AABBWHD3D(pt.get(minmaxX.getMin()), abs(minmaxX.getMax() - minmaxX.getMin()), abs(minmaxY.getMax() - minmaxY.getMin()), abs(minmaxZ.getMax() - minmaxZ.getMin()));
}

AABBCR2D createAABBCR2D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  PVector center = PVector.add(new PVector(minx.x,miny.y), new PVector(maxx.x,maxy.y)).mult(0.5f);
  float radiusX = abs(maxx.x - minx.x) * 0.5f;
  float radiusY = abs(maxy.y - miny.y) * 0.5f;
  return new AABBCR2D(center, radiusX, radiusY);

  //PVector center = PVector.add(pt.get(minmaxX.getMin()), pt.get(minmaxX.getMax())).mult(0.5f);
  //float radiusX = abs(minmaxX.getMax() - minmaxX.getMin()) * 0.5f;
  //float radiusY = abs(minmaxY.getMax() - minmaxY.getMin()) * 0.5f;
  //return new AABBCR2D(center, radiusX, radiusY);
}

AABBCR3D createAABBCR3D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
  MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  var minz = pt.get(minmaxZ.getMin());
  var maxz = pt.get(minmaxZ.getMax());
  PVector center = PVector.add(new PVector(minx.x, miny.y, minz.z), new PVector(maxx.x, maxy.y, maxz.z)).mult(0.5f);
  float radiusX = abs(maxx.x - minx.x) * 0.5f;
  float radiusY = abs(maxy.y - miny.y) * 0.5f;
  float radiusZ = abs(maxz.z - minz.z) * 0.5f;
  return new AABBCR3D(center, radiusX, radiusY, radiusZ);

  //PVector center = PVector.add(pt.get(minmaxX.getMin()), pt.get(minmaxX.getMax())).mult(0.5f);
  //float radiusX = abs(minmaxX.getMax() - minmaxX.getMin()) * 0.5f;
  //float radiusY = abs(minmaxY.getMax() - minmaxY.getMin()) * 0.5f;
  //float radiusZ = abs(minmaxZ.getMax() - minmaxZ.getMin()) * 0.5f;
  //return new AABBCR3D(center, radiusX, radiusY, radiusZ);
}

Util

戻り値まとめ用クラス


class MinMaxIndex {
  private int min;
  private int max;

  // Constructor
  MinMaxIndex(int min, int max) {
    this.min = min;
    this.max = max;
  }

  // Accessors
  int getMin() { return min; }
  void setMin(int min) { this.min = min; }
  int getMax() { return max; }
  void setMax(int max) { this.max = max; }
}


Hit & Draggまで

main


import java.util.Collections;
import java.util.Comparator;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;
import java.util.Stack;
import java.util.Arrays;
import processing.svg.*;

import java.util.List;
import java.util.Collection;
import java.util.stream.Collectors;

import processing.opengl.*;

void setup()
{
  size(500,500);
  background(255);
    
  var o1 = new Object2D();
  var o2 = new Object2D();
  var o3 = new Object2D();
  this.Objects.add(o1);
  this.Objects.add(o2);
  this.Objects.add(o3);
}

void draw()
{
  background(255);
  noFill();
  strokeWeight(1);
  
  for(var obj : this.Objects)
  {
    if(obj instanceof IUpdatable)
    {
      ((IUpdatable)obj).update();
    }    
    if(obj instanceof IDrawable)
    {
      ((IDrawable)obj).draw();
    }
  }
}


//全てのオブジェクト。このリストはGUI機能を持つオブジェクトを含むことがある。
List<IObject> Objects = new ArrayList<IObject>();
IObject CurrentObject = null;

class Object2D implements IObject, HasBoundingVolume2D, IUpdatable, IDrawable
{
  IBV2D BV;
  IBV2D GetBV()
  {
    return this.BV;
  }
  
  List<PVector> coordinates = new ArrayList<PVector>();
  
  Object2D()
  {
    makeRandom(10);
    
    var aabb = createAABBMinMax2D(this.coordinates);
    this.BV = aabb;
  }
  
  void makeRandom(int count)
  {
    for(int i = 0; i<count; i++)
    {
      var v = new PVector(random(width),random(height));
      this.coordinates.add(v);
    }    
  }
  
  void draw()
  {
    drawCoords();
    drawBV();
  }
  
  void update()
  {
    //updateBV();
    
    //完全再計算
    this.BV = createAABBMinMax2D(this.coordinates);
  }
  
  void drawBV()
  {    
    IAABBMinMax2D aabbmm = (IAABBMinMax2D)this.BV;
    var ltv = aabbmm.GetLTV();
    var rbv = aabbmm.GetRBV();    
    var w = abs(rbv.x-ltv.x);
    var h = abs(rbv.y-ltv.y);    
    rect(ltv.x,ltv.y,w,h);
  }
  
  void updateBV()
  {

  }
  
  void drawCoords()
  {
    for(var v : this.coordinates)
    {
      circle(v.x,v.y,5);
    }
  }  
}



PVector pprev;
PVector prev;
PVector current;
PVector dv = new PVector(0,0);
void mousePressed()
{
 pprev = new PVector(mouseX,mouseY);
 prev = new PVector(mouseX,mouseY);
 current = new PVector(mouseX,mouseY);  
 
 for(int i = 0; i<this.Objects.size(); i++)
 {
   IObject obj = this.Objects.get(i);
   if(obj instanceof HasBoundingVolume2D)
   {
     var volume = ((HasBoundingVolume2D)obj).GetBV();
     if(volume.Hit(mouseX,mouseY))
     {
       CurrentObject = obj;
     }
   }
 }   
}

//ボタンが押されていない時
void mouseMoved(){
}

//ボタンが押されている時
void mouseDragged(){
   if(pprev==null){return;}
   pprev = prev.copy();
   if(prev==null){return;}
   prev = current.copy();
   current.x = mouseX;
   current.y = mouseY;  
   dv = PVector.sub(current,prev);  
   
   if(CurrentObject!=null && CurrentObject instanceof Object2D)
   {
     for(var v : ((Object2D)CurrentObject).coordinates)
     {
       v.add(dv);
     }
   }
}

void mouseReleased()
{   
   pprev = null;
   prev = null;
   current = null;
   
   CurrentObject=null;
}

interface IObject{}

//これらにHit()を持たせるか否か
//p77
//bounding volume
interface IBV2D extends IHit2D{}
interface IBV3D extends IHit3D{}

interface HasBoundingVolume2D
{
  IBV2D GetBV();
}
interface HasBoundingVolume3D
{
  IBV3D GetBV();
}

interface IUpdatable
{
  void update();
}

interface IDrawable
{
  void draw(); 
}

interface IGUI extends IDrawable
{  
 //void draw(); 
 void draw(float x, float y);
}

interface IHit2D
{
 boolean Hit(float x, float y);
}
interface IHit3D
{
 boolean Hit(float x, float y, float z);
}

interface ITranslate
{
 void Translate(PVector dv);
}

interface HasOrigin
{
 PVector GetOrigin();
}

interface IClickable
{
 void mousePressed();
 void mouseReleased(); 
}

interface IDraggable
{  
 void mouseDragged();  
}


AABB


////////////////////////////////////////////////////

//axis-aligned bounding box
interface IAABBMinMax2D extends IBV2D
{
  PVector GetLTV();//left top vector
  PVector GetRBV();//right bottom vector
}

//processingの場合は2Dも3DもPVectorでまかなえる
interface IAABBMinMax3D extends IBV3D
{
  PVector GetLTV();//left top vector
  PVector GetRBV();//right bottom vector
}

interface IAABBWH2D extends IBV2D
{
  PVector GetLTV();
  float GetWidth();
  float GetHeight();
}

interface IAABBWHD3D extends IBV3D
{
  PVector GetLTV();
  float GetWidth();
  float GetHeight();
  float GetDepth();
}

//center radius
interface IAABBCR2D extends IBV2D
{
  PVector GetCV();
  float GetRX();
  float GetRY();
}

interface IAABBCR3D extends IBV3D
{
  PVector GetCV();
  float GetRX();
  float GetRY();
  float GetRZ();
}

class AABBMinMax2D implements IAABBMinMax2D {
  PVector LTV, RBV;

  AABBMinMax2D(PVector LTV, PVector RBV) {
    this.LTV = LTV;
    this.RBV = RBV;
  }

  public PVector GetLTV() { return this.LTV; }
  public PVector GetRBV() { return this.RBV; }
  boolean Hit(float x, float y) {
    return checkHit(this, new PVector(x,y)); }
}

class AABBMinMax3D implements IAABBMinMax3D {
  PVector LTV, RBV;

  AABBMinMax3D(PVector LTV, PVector RBV) {
    this.LTV = LTV;
    this.RBV = RBV;
  }

  public PVector GetLTV() { return this.LTV; }
  public PVector GetRBV() { return this.RBV; }
  boolean Hit(float x, float y, float z) {
    return checkHit(this, new PVector(x,y,z)); }  
}

class AABBWH2D implements IAABBWH2D {
  PVector LTV;
  float width, height;

  AABBWH2D(PVector LTV, float width, float height) {
    this.LTV = LTV;
    this.width = width;
    this.height = height;
  }

  public PVector GetLTV() { return this.LTV; }
  public float GetWidth() { return this.width; }
  public float GetHeight() { return this.height; }
  boolean Hit(float x, float y) {
    return checkHit(this, new PVector(x,y)); }  
}

class AABBWHD3D implements IAABBWHD3D {
  PVector LTV;
  float width, height, depth;

  AABBWHD3D(PVector LTV, float width, float height, float depth) {
    this.LTV = LTV;
    this.width = width;
    this.height = height;
    this.depth = depth;
  }

  public PVector GetLTV() { return this.LTV; }
  public float GetWidth() { return this.width; }
  public float GetHeight() { return this.height; }
  public float GetDepth() { return this.depth; }
  boolean Hit(float x, float y, float z) {
    return checkHit(this, new PVector(x,y,z)); }  
}

class AABBCR2D implements IAABBCR2D {
  PVector CV;
  float rx;
  float ry;

  AABBCR2D(PVector CV, float rx, float ry) {
    this.CV = CV;
    this.rx = rx;
    this.ry = ry;
  }

  public PVector GetCV() { return this.CV; }
  public float GetRX() { return this.rx; }
  public float GetRY() { return this.ry; }
  boolean Hit(float x, float y) {
    return checkHit(this, new PVector(x,y)); }  
}

class AABBCR3D implements IAABBCR3D {
  PVector CV;
  float rx;
  float ry;
  float rz;

  AABBCR3D(PVector CV, float rx, float ry, float rz) {
    this.CV = CV;
    this.rx=rx;
    this.ry=ry;
    this.rz=rz;
  }

  public PVector GetCV() { return this.CV; }
  public float GetRX() { return this.rx; }
  public float GetRY() { return this.ry; }
  public float GetRZ() { return this.rz; }  

  boolean Hit(float x, float y, float z) {
    return checkHit(this, new PVector(x,y,z)); }  
}


///////////////////////////////////////////////////////////////////////////


MinMaxIndex extremePointsAlongDirection(PVector dir, List<PVector> pt) 
{
  MinMaxIndex minmax = new MinMaxIndex(0, 0);
  float minproj = Float.MAX_VALUE;
  float maxproj = -Float.MAX_VALUE;
  
  for (int i = 0; i < pt.size(); i++) {
    // Project vector from origin to point onto direction vector
    float proj = pt.get(i).dot(dir);
    
    // Keep track of least distant point along direction vector
    if (proj < minproj) {
      minproj = proj;
      minmax.setMin(i);
    }    
    // Keep track of most distant point along direction vector
    if (proj > maxproj) {
      maxproj = proj;
      minmax.setMax(i);
    }
  }
  return minmax;
}

AABBMinMax2D createAABBMinMax2D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  return new AABBMinMax2D(new PVector(minx.x,miny.y), new PVector(maxx.x,maxy.y));
  
  //return new AABBMinMax2D(pt.get(minmaxX.getMin()), pt.get(minmaxY.getMax()));
}

AABBMinMax3D createAABBMinMax3D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
  MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  var minz = pt.get(minmaxZ.getMin());
  var maxz = pt.get(minmaxZ.getMax());
  
  return new AABBMinMax3D(new PVector(minx.x,miny.y,minz.z), new PVector(maxx.x,maxy.y,maxz.z));
  
  //return new AABBMinMax3D(pt.get(minmaxX.getMin()), pt.get(minmaxZ.getMax()));
}

AABBWH2D createAABBWH2D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  return new AABBWH2D(new PVector(minx.x,miny.y), abs(maxx.x - minx.x), abs(maxy.y - miny.y));

  //return new AABBWH2D(pt.get(minmaxX.getMin()), abs(minmaxX.getMax() - minmaxX.getMin()), abs(minmaxY.getMax() - minmaxY.getMin()));
}

AABBWHD3D createAABBWHD3D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
  MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  var minz = pt.get(minmaxZ.getMin());
  var maxz = pt.get(minmaxZ.getMax());
  return new AABBWHD3D(new PVector(minx.x, miny.y, minz.z), abs(maxx.x - minx.x), abs(maxy.y - miny.y), abs(maxz.z - minz.z));

  //return new AABBWHD3D(pt.get(minmaxX.getMin()), abs(minmaxX.getMax() - minmaxX.getMin()), abs(minmaxY.getMax() - minmaxY.getMin()), abs(minmaxZ.getMax() - minmaxZ.getMin()));
}

AABBCR2D createAABBCR2D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  PVector center = PVector.add(new PVector(minx.x,miny.y), new PVector(maxx.x,maxy.y)).mult(0.5f);
  float radiusX = abs(maxx.x - minx.x) * 0.5f;
  float radiusY = abs(maxy.y - miny.y) * 0.5f;
  return new AABBCR2D(center, radiusX, radiusY);

  //PVector center = PVector.add(pt.get(minmaxX.getMin()), pt.get(minmaxX.getMax())).mult(0.5f);
  //float radiusX = abs(minmaxX.getMax() - minmaxX.getMin()) * 0.5f;
  //float radiusY = abs(minmaxY.getMax() - minmaxY.getMin()) * 0.5f;
  //return new AABBCR2D(center, radiusX, radiusY);
}

AABBCR3D createAABBCR3D(List<PVector> pt) {
  MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
  MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
  MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
  
  var minx = pt.get(minmaxX.getMin());
  var maxx = pt.get(minmaxX.getMax());
  var miny = pt.get(minmaxY.getMin());
  var maxy = pt.get(minmaxY.getMax());
  var minz = pt.get(minmaxZ.getMin());
  var maxz = pt.get(minmaxZ.getMax());
  PVector center = PVector.add(new PVector(minx.x, miny.y, minz.z), new PVector(maxx.x, maxy.y, maxz.z)).mult(0.5f);
  float radiusX = abs(maxx.x - minx.x) * 0.5f;
  float radiusY = abs(maxy.y - miny.y) * 0.5f;
  float radiusZ = abs(maxz.z - minz.z) * 0.5f;
  return new AABBCR3D(center, radiusX, radiusY, radiusZ);

  //PVector center = PVector.add(pt.get(minmaxX.getMin()), pt.get(minmaxX.getMax())).mult(0.5f);
  //float radiusX = abs(minmaxX.getMax() - minmaxX.getMin()) * 0.5f;
  //float radiusY = abs(minmaxY.getMax() - minmaxY.getMin()) * 0.5f;
  //float radiusZ = abs(minmaxZ.getMax() - minmaxZ.getMin()) * 0.5f;
  //return new AABBCR3D(center, radiusX, radiusY, radiusZ);
}


Hit




// For AABB defined with min-max vectors
boolean checkHit(IAABBMinMax2D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = aabb.GetRBV();
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y;
}

boolean checkHit(IAABBMinMax3D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = aabb.GetRBV();
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y && point.z >= min.z && point.z <= max.z;
}

// For AABB defined with a vector and dimensions
boolean checkHit(IAABBWH2D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = PVector.add(min, new PVector(aabb.GetWidth(), aabb.GetHeight()));
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y;
}

boolean checkHit(IAABBWHD3D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = PVector.add(min, new PVector(aabb.GetWidth(), aabb.GetHeight(), aabb.GetDepth()));
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y && point.z >= min.z && point.z <= max.z;
}

// For AABB defined with center and radius
boolean checkHit(IAABBCR2D aabb, PVector point) {
  PVector center = aabb.GetCV();
  float rx = aabb.GetRX();
  float ry = aabb.GetRY();
  
  return point.x >= center.x - rx && point.x <= center.x + rx && point.y >= center.y - ry && point.y <= center.y + ry;
}

boolean checkHit(IAABBCR3D aabb, PVector point) {
  PVector center = aabb.GetCV();
  float rx = aabb.GetRX();
  float ry = aabb.GetRY();
  float rz = aabb.GetRZ();
  
  return point.x >= center.x - rx && point.x <= center.x + rx && point.y >= center.y - ry && point.y <= center.y + ry && point.z >= center.z - rz && point.z <= center.z + rz;
}

Util


class MinMaxIndex {
  private int min;
  private int max;

  // Constructor
  MinMaxIndex(int min, int max) {
    this.min = min;
    this.max = max;
  }

  // Accessors
  int getMin() { return min; }
  void setMin(int min) { this.min = min; }
  int getMax() { return max; }
  void setMax(int max) { this.max = max; }
}

Sphere追加


GenerateBoundingVolumeを関数型インターフェースへ。
DrawBoundingVolume系は極めて雑。

main


import java.util.Collections;
import java.util.Comparator;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Queue;
import java.util.Stack;
import java.util.Arrays;
import processing.svg.*;

import java.util.List;
import java.util.Collection;
import java.util.stream.Collectors;

import processing.opengl.*;

void setup()
{
  size(500,500);
  background(255);
    
  var o1 = new Object2D();
  var o2 = new Object2D();
  var o3 = new Object2D();
  this.Objects.add(o1);
  this.Objects.add(o2);
  this.Objects.add(o3);
}

void draw()
{
  background(255);
  noFill();
  strokeWeight(1);
  
  for(var obj : this.Objects)
  {
    if(obj instanceof IUpdatable)
    {
      ((IUpdatable)obj).update();
    }    
    if(obj instanceof IDrawable)
    {
      ((IDrawable)obj).draw();
    }
  }
}


//全てのオブジェクト。このリストはGUI機能を持つオブジェクトを含むことがある。
List<IObject> Objects = new ArrayList<IObject>();
IObject CurrentObject = null;

public interface GenerateBV2DMethod {
    IBV2D exe(List<PVector> coords);    
    //AABBMinMax2D exe(List<PVector> coords);    
}

class Object2D implements IObject, HasBoundingVolume2D, IUpdatable, IDrawable
{
  IBV2D BV;
  IBV2D GetBV()
  {
    return this.BV;
  }
  
  List<PVector> coordinates = new ArrayList<PVector>();
  
  GenerateBV2DMethod GenBVMethod;
  void GenBV()
  {
    var aabb = this.GenBVMethod.exe(this.coordinates);    
    this.BV = aabb;    
  }
  
  Object2D()
  {
    this.coordinates = makeRandomCoords(10, 100);
    
    //this.GenBVMethod = (List<PVector> coords) -> createAABBMinMax2D(coords);
    this.GenBVMethod = (List<PVector> coords) -> createBVCircleLoose(coords.get(0),coords);
            
    this.GenBV();
  }
  
  void draw()
  {
    drawCoords();
    drawBV();
  }
  
  void update()
  {
    //updateBV();
    
    //完全再計算
    //this.BV = createAABBMinMax2D(this.coordinates);
    this.GenBV();
  }
  
  void drawBV()
  {       
    if(this.BV instanceof IAABBMinMax2D)
    {
      IAABBMinMax2D aabbmm = (IAABBMinMax2D)this.BV;
      drawAABBMinMax2D(aabbmm);
    }
    else if(this.BV instanceof IBVCircle2D)
    {
      IBVCircle2D bvc = (IBVCircle2D)this.BV;
      drawBVCircle2D(bvc);
    }
  }
  
  void updateBV()
  {

  }
  
  void drawCoords()
  {
    for(var v : this.coordinates)
    {
      circle(v.x,v.y,5);
    }
  }  
}

PVector pprev;
PVector prev;
PVector current;
PVector dv = new PVector(0,0);
void mousePressed()
{
 pprev = new PVector(mouseX,mouseY);
 prev = new PVector(mouseX,mouseY);
 current = new PVector(mouseX,mouseY);  
 
 for(int i = 0; i<this.Objects.size(); i++)
 {
   IObject obj = this.Objects.get(i);
   if(obj instanceof HasBoundingVolume2D)
   {
     var volume = ((HasBoundingVolume2D)obj).GetBV();
     if(volume.Hit(mouseX,mouseY))
     {
       CurrentObject = obj;
     }
   }
 }   
}

//ボタンが押されていない時
void mouseMoved(){
}

//ボタンが押されている時
void mouseDragged(){
   if(pprev==null){return;}
   pprev = prev.copy();
   if(prev==null){return;}
   prev = current.copy();
   current.x = mouseX;
   current.y = mouseY;  
   dv = PVector.sub(current,prev);  
   
   if(CurrentObject!=null && CurrentObject instanceof Object2D)
   {
     for(var v : ((Object2D)CurrentObject).coordinates)
     {
       v.add(dv);
     }
   }
}

void mouseReleased()
{   
   pprev = null;
   prev = null;
   current = null;
   
   CurrentObject=null;
}

interface IObject{}

//これらにHit()を持たせるか否か
//p77
//bounding volume
interface IBV2D extends IHit2D{}
interface IBV3D extends IHit3D{}

interface HasBoundingVolume2D
{
  IBV2D GetBV();
}
interface HasBoundingVolume3D
{
  IBV3D GetBV();
}

interface IUpdatable
{
  void update();
}

interface IDrawable
{
  void draw(); 
}

interface IGUI extends IDrawable
{  
 //void draw(); 
 void draw(float x, float y);
}

interface IHit2D
{
 boolean Hit(float x, float y);
}
interface IHit3D
{
 boolean Hit(float x, float y, float z);
}

interface ITranslate
{
 void Translate(PVector dv);
}

interface HasOrigin
{
 PVector GetOrigin();
}

interface IClickable
{
 void mousePressed();
 void mouseReleased(); 
}

interface IDraggable
{  
 void mouseDragged();  
}

AABB

////////////////////////////////////////////////////

//axis-aligned bounding box
interface IAABBMinMax2D extends IBV2D
{
  PVector GetLTV();//left top vector
  PVector GetRBV();//right bottom vector
}

//processingの場合は2Dも3DもPVectorでまかなえる
interface IAABBMinMax3D extends IBV3D
{
  PVector GetLTV();//left top vector
  PVector GetRBV();//right bottom vector
}

interface IAABBWH2D extends IBV2D
{
  PVector GetLTV();
  float GetWidth();
  float GetHeight();
}

interface IAABBWHD3D extends IBV3D
{
  PVector GetLTV();
  float GetWidth();
  float GetHeight();
  float GetDepth();
}

//center radius
interface IAABBCR2D extends IBV2D
{
  PVector GetCV();
  float GetRX();
  float GetRY();
}

interface IAABBCR3D extends IBV3D
{
  PVector GetCV();
  float GetRX();
  float GetRY();
  float GetRZ();
}

class AABBMinMax2D implements IAABBMinMax2D {
  PVector LTV, RBV;

  AABBMinMax2D(PVector LTV, PVector RBV) {
    this.LTV = LTV;
    this.RBV = RBV;
  }

  public PVector GetLTV() { return this.LTV; }
  public PVector GetRBV() { return this.RBV; }
  boolean Hit(float x, float y) {
    return checkHit(this, new PVector(x,y)); }
}

class AABBMinMax3D implements IAABBMinMax3D {
  PVector LTV, RBV;

  AABBMinMax3D(PVector LTV, PVector RBV) {
    this.LTV = LTV;
    this.RBV = RBV;
  }

  public PVector GetLTV() { return this.LTV; }
  public PVector GetRBV() { return this.RBV; }
  boolean Hit(float x, float y, float z) {
    return checkHit(this, new PVector(x,y,z)); }  
}

class AABBWH2D implements IAABBWH2D {
  PVector LTV;
  float width, height;

  AABBWH2D(PVector LTV, float width, float height) {
    this.LTV = LTV;
    this.width = width;
    this.height = height;
  }

  public PVector GetLTV() { return this.LTV; }
  public float GetWidth() { return this.width; }
  public float GetHeight() { return this.height; }
  boolean Hit(float x, float y) {
    return checkHit(this, new PVector(x,y)); }  
}

class AABBWHD3D implements IAABBWHD3D {
  PVector LTV;
  float width, height, depth;

  AABBWHD3D(PVector LTV, float width, float height, float depth) {
    this.LTV = LTV;
    this.width = width;
    this.height = height;
    this.depth = depth;
  }

  public PVector GetLTV() { return this.LTV; }
  public float GetWidth() { return this.width; }
  public float GetHeight() { return this.height; }
  public float GetDepth() { return this.depth; }
  boolean Hit(float x, float y, float z) {
    return checkHit(this, new PVector(x,y,z)); }  
}

class AABBCR2D implements IAABBCR2D {
  PVector CV;
  float rx;
  float ry;

  AABBCR2D(PVector CV, float rx, float ry) {
    this.CV = CV;
    this.rx = rx;
    this.ry = ry;
  }

  public PVector GetCV() { return this.CV; }
  public float GetRX() { return this.rx; }
  public float GetRY() { return this.ry; }
  boolean Hit(float x, float y) {
    return checkHit(this, new PVector(x,y)); }  
}

class AABBCR3D implements IAABBCR3D {
  PVector CV;
  float rx;
  float ry;
  float rz;

  AABBCR3D(PVector CV, float rx, float ry, float rz) {
    this.CV = CV;
    this.rx=rx;
    this.ry=ry;
    this.rz=rz;
  }

  public PVector GetCV() { return this.CV; }
  public float GetRX() { return this.rx; }
  public float GetRY() { return this.ry; }
  public float GetRZ() { return this.rz; }  

  boolean Hit(float x, float y, float z) {
    return checkHit(this, new PVector(x,y,z)); }  
}


///////////////////////////////////////////////////////////////////////////



  MinMaxIndex extremePointsAlongDirection(PVector dir, List<PVector> pt) 
  {
    MinMaxIndex minmax = new MinMaxIndex(0, 0);
    float minproj = Float.MAX_VALUE;
    float maxproj = -Float.MAX_VALUE;
    
    for (int i = 0; i < pt.size(); i++) {
      // Project vector from origin to point onto direction vector
      float proj = pt.get(i).dot(dir);
      
      // Keep track of least distant point along direction vector
      if (proj < minproj) {
        minproj = proj;
        minmax.setMin(i);
      }    
      // Keep track of most distant point along direction vector
      if (proj > maxproj) {
        maxproj = proj;
        minmax.setMax(i);
      }
    }
    return minmax;
  }
    
  
  AABBMinMax2D createAABBMinMax2D(List<PVector> pt) {
    MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
    MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
    
    var minx = pt.get(minmaxX.getMin());
    var maxx = pt.get(minmaxX.getMax());
    var miny = pt.get(minmaxY.getMin());
    var maxy = pt.get(minmaxY.getMax());
    return new AABBMinMax2D(new PVector(minx.x,miny.y), new PVector(maxx.x,maxy.y));
    
    //return new AABBMinMax2D(pt.get(minmaxX.getMin()), pt.get(minmaxY.getMax()));
  }
  
  void drawAABBMinMax2D(IAABBMinMax2D aabbmm)
  {
    var ltv = aabbmm.GetLTV();
    var rbv = aabbmm.GetRBV();    
    var w = abs(rbv.x-ltv.x);
    var h = abs(rbv.y-ltv.y);    
    rect(ltv.x,ltv.y,w,h);    
  }
  
  AABBMinMax3D createAABBMinMax3D(List<PVector> pt) {
    MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
    MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
    MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
    
    var minx = pt.get(minmaxX.getMin());
    var maxx = pt.get(minmaxX.getMax());
    var miny = pt.get(minmaxY.getMin());
    var maxy = pt.get(minmaxY.getMax());
    var minz = pt.get(minmaxZ.getMin());
    var maxz = pt.get(minmaxZ.getMax());
    
    return new AABBMinMax3D(new PVector(minx.x,miny.y,minz.z), new PVector(maxx.x,maxy.y,maxz.z));
    
    //return new AABBMinMax3D(pt.get(minmaxX.getMin()), pt.get(minmaxZ.getMax()));
  }
  
  AABBWH2D createAABBWH2D(List<PVector> pt) {
    MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
    MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
    
    var minx = pt.get(minmaxX.getMin());
    var maxx = pt.get(minmaxX.getMax());
    var miny = pt.get(minmaxY.getMin());
    var maxy = pt.get(minmaxY.getMax());
    return new AABBWH2D(new PVector(minx.x,miny.y), abs(maxx.x - minx.x), abs(maxy.y - miny.y));
  
    //return new AABBWH2D(pt.get(minmaxX.getMin()), abs(minmaxX.getMax() - minmaxX.getMin()), abs(minmaxY.getMax() - minmaxY.getMin()));
  }
  
  AABBWHD3D createAABBWHD3D(List<PVector> pt) {
    MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
    MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
    MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
    
    var minx = pt.get(minmaxX.getMin());
    var maxx = pt.get(minmaxX.getMax());
    var miny = pt.get(minmaxY.getMin());
    var maxy = pt.get(minmaxY.getMax());
    var minz = pt.get(minmaxZ.getMin());
    var maxz = pt.get(minmaxZ.getMax());
    return new AABBWHD3D(new PVector(minx.x, miny.y, minz.z), abs(maxx.x - minx.x), abs(maxy.y - miny.y), abs(maxz.z - minz.z));
  
    //return new AABBWHD3D(pt.get(minmaxX.getMin()), abs(minmaxX.getMax() - minmaxX.getMin()), abs(minmaxY.getMax() - minmaxY.getMin()), abs(minmaxZ.getMax() - minmaxZ.getMin()));
  }
  
  AABBCR2D createAABBCR2D(List<PVector> pt) {
    MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0), pt);
    MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1), pt);
    
    var minx = pt.get(minmaxX.getMin());
    var maxx = pt.get(minmaxX.getMax());
    var miny = pt.get(minmaxY.getMin());
    var maxy = pt.get(minmaxY.getMax());
    PVector center = PVector.add(new PVector(minx.x,miny.y), new PVector(maxx.x,maxy.y)).mult(0.5f);
    float radiusX = abs(maxx.x - minx.x) * 0.5f;
    float radiusY = abs(maxy.y - miny.y) * 0.5f;
    return new AABBCR2D(center, radiusX, radiusY);
  
    //PVector center = PVector.add(pt.get(minmaxX.getMin()), pt.get(minmaxX.getMax())).mult(0.5f);
    //float radiusX = abs(minmaxX.getMax() - minmaxX.getMin()) * 0.5f;
    //float radiusY = abs(minmaxY.getMax() - minmaxY.getMin()) * 0.5f;
    //return new AABBCR2D(center, radiusX, radiusY);
  }
  
  AABBCR3D createAABBCR3D(List<PVector> pt) {
    MinMaxIndex minmaxX = extremePointsAlongDirection(new PVector(1, 0, 0), pt);
    MinMaxIndex minmaxY = extremePointsAlongDirection(new PVector(0, 1, 0), pt);
    MinMaxIndex minmaxZ = extremePointsAlongDirection(new PVector(0, 0, 1), pt);
    
    var minx = pt.get(minmaxX.getMin());
    var maxx = pt.get(minmaxX.getMax());
    var miny = pt.get(minmaxY.getMin());
    var maxy = pt.get(minmaxY.getMax());
    var minz = pt.get(minmaxZ.getMin());
    var maxz = pt.get(minmaxZ.getMax());
    PVector center = PVector.add(new PVector(minx.x, miny.y, minz.z), new PVector(maxx.x, maxy.y, maxz.z)).mult(0.5f);
    float radiusX = abs(maxx.x - minx.x) * 0.5f;
    float radiusY = abs(maxy.y - miny.y) * 0.5f;
    float radiusZ = abs(maxz.z - minz.z) * 0.5f;
    return new AABBCR3D(center, radiusX, radiusY, radiusZ);
  
    //PVector center = PVector.add(pt.get(minmaxX.getMin()), pt.get(minmaxX.getMax())).mult(0.5f);
    //float radiusX = abs(minmaxX.getMax() - minmaxX.getMin()) * 0.5f;
    //float radiusY = abs(minmaxY.getMax() - minmaxY.getMin()) * 0.5f;
    //float radiusZ = abs(minmaxZ.getMax() - minmaxZ.getMin()) * 0.5f;
    //return new AABBCR3D(center, radiusX, radiusY, radiusZ);
  }  

Sphere


//////////////////////////////////////////////////////////////////////////////

interface IBVCircle2D extends IBV2D
{
  PVector GetCV();
  void SetCV(PVector cv);
  float GetRadius();
  void SetRadius(float value);
}

interface IBVSphere3D extends IBV3D
{
  PVector GetCV();
  void SetCV(PVector cv);
  float GetRadius();  
  void SetRadius(float value);
}

/////////////////////////////////////////////

class BVCircle2D implements IBVCircle2D {
  private PVector center;
  private float radius;

  BVCircle2D(PVector center, float radius) {
    this.center = center;
    this.radius = radius;
  }

  public PVector GetCV() {return this.center;}
  public void SetCV(PVector cv){this.center.set(cv);}
  public float GetRadius() {return this.radius;}
  public void SetRadius(float value) {this.radius=value;}
  
  boolean Hit(float x, float y)
  {
    return checkHit(this, new PVector(x,y));
  }
}

class BVSphere3D implements IBVSphere3D {
  private PVector center;
  private float radius;

  BVSphere3D(){}
  
  BVSphere3D(PVector center, float radius) {
    this.center = center;
    this.radius = radius;
  }

  public PVector GetCV() {
    return this.center;
  }
  public void SetCV(PVector cv){
    this.center.set(cv);
  }

  public float GetRadius() {
    return this.radius;
  }
  public void SetRadius(float value) {
    this.radius=value;
  }  
  
  boolean Hit(float x, float y, float z)
  {
    return checkHit(this, new PVector(x,y,z));
  }
}

////////////////////////////////////////////

//基準点から最も遠い点までの距離を計算する
float CalcuFarthestDistance(PVector origin, List<PVector> pt)
{
  float farthest = 0;
  for(var p : pt)
  {
    var length = PVector.sub(p,origin).mag();
    if(farthest<=length)
    {
      farthest=length;      
    }
  }
  return farthest;
}

//オブジェクトが回転したとしても収まるような大きめの円、球をBVとして作成
BVCircle2D createBVCircleLoose(PVector origin, List<PVector> pt) {
  var radius = CalcuFarthestDistance(origin, pt);
  return new BVCircle2D(origin, radius);
}

void drawBVCircle2D(IBVCircle2D bvc)
{
  ellipseMode(RADIUS);
  circle(bvc.GetCV().x, bvc.GetCV().y, bvc.GetRadius());
}


BVSphere3D createBVSphereLoose(PVector origin, List<PVector> pt) {
  var radius = CalcuFarthestDistance(origin, pt);
  return new BVSphere3D(origin, radius);
}

Hit



boolean checkHit(IBVCircle2D circle, PVector point) {
  // Get the circle's center vector and radius
  PVector cv = circle.GetCV();
  float radius = circle.GetRadius();
  
  // Compute the distance from the point to the center
  float dist = PVector.dist(point, cv);
  
  // If the distance is less than or equal to the radius, the point is inside the circle
  return dist <= radius;
}

boolean checkHit(IBVSphere3D sphere, PVector point) {
  // Get the sphere's center vector and radius
  PVector cv = sphere.GetCV();
  float radius = sphere.GetRadius();
  
  // Compute the distance from the point to the center
  float dist = PVector.dist(point, cv);
  
  // If the distance is less than or equal to the radius, the point is inside the sphere
  return dist <= radius;
}


boolean TestSphereSphere(IBVSphere3D a, IBVSphere3D b) {
  // Calculate squared distance between centers
  PVector d = PVector.sub(a.GetCV(), b.GetCV());
  float dist2 = d.magSq(); // Get the magnitude squared of vector d
  // Spheres intersect if squared distance is less than squared sum of radii
  float radiusSum = a.GetRadius() + b.GetRadius();
  return dist2 <= radiusSum * radiusSum;
}


// For AABB defined with min-max vectors
boolean checkHit(IAABBMinMax2D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = aabb.GetRBV();
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y;
}

boolean checkHit(IAABBMinMax3D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = aabb.GetRBV();
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y && point.z >= min.z && point.z <= max.z;
}

// For AABB defined with a vector and dimensions
boolean checkHit(IAABBWH2D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = PVector.add(min, new PVector(aabb.GetWidth(), aabb.GetHeight()));
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y;
}

boolean checkHit(IAABBWHD3D aabb, PVector point) {
  PVector min = aabb.GetLTV();
  PVector max = PVector.add(min, new PVector(aabb.GetWidth(), aabb.GetHeight(), aabb.GetDepth()));
  
  return point.x >= min.x && point.x <= max.x && point.y >= min.y && point.y <= max.y && point.z >= min.z && point.z <= max.z;
}

// For AABB defined with center and radius
boolean checkHit(IAABBCR2D aabb, PVector point) {
  PVector center = aabb.GetCV();
  float rx = aabb.GetRX();
  float ry = aabb.GetRY();
  
  return point.x >= center.x - rx && point.x <= center.x + rx && point.y >= center.y - ry && point.y <= center.y + ry;
}

boolean checkHit(IAABBCR3D aabb, PVector point) {
  PVector center = aabb.GetCV();
  float rx = aabb.GetRX();
  float ry = aabb.GetRY();
  float rz = aabb.GetRZ();
  
  return point.x >= center.x - rx && point.x <= center.x + rx && point.y >= center.y - ry && point.y <= center.y + ry && point.z >= center.z - rz && point.z <= center.z + rz;
}


boolean TestAABBAABB(IAABBMinMax2D a, IAABBMinMax2D b) {
  // Exit with no intersection if separated along an axis
  if (a.GetRBV().x < b.GetLTV().x || a.GetLTV().x > b.GetRBV().x) return false;
  if (a.GetRBV().y < b.GetLTV().y || a.GetLTV().y > b.GetRBV().y) return false;
  
  // Overlapping on all axes means AABBs are intersecting
  return true;
}

boolean TestAABBAABB(IAABBMinMax3D a, IAABBMinMax3D b) {
  // Exit with no intersection if separated along an axis
  if (a.GetRBV().x < b.GetLTV().x || a.GetLTV().x > b.GetRBV().x) return false;
  if (a.GetRBV().y < b.GetLTV().y || a.GetLTV().y > b.GetRBV().y) return false;
  if (a.GetRBV().z < b.GetLTV().z || a.GetLTV().z > b.GetRBV().z) return false;
  
  // Overlapping on all axes means AABBs are intersecting
  return true;
}



boolean TestAABBAABB(IAABBWH2D a, IAABBWH2D b) {
  float t;
  
  // x axis
  if ((t = a.GetLTV().x - b.GetLTV().x) > b.GetWidth() || -t > a.GetWidth()) 
    return false;

  // y axis
  if ((t = a.GetLTV().y - b.GetLTV().y) > b.GetHeight() || -t > a.GetHeight()) 
    return false;

  // if not separated along any axis, AABBs are intersecting
  return true;
}

boolean TestAABBAABB(IAABBWHD3D a, IAABBWHD3D b) {
  float t;
  
  // x axis
  if ((t = a.GetLTV().x - b.GetLTV().x) > b.GetWidth() || -t > a.GetWidth()) 
    return false;

  // y axis
  if ((t = a.GetLTV().y - b.GetLTV().y) > b.GetHeight() || -t > a.GetHeight()) 
    return false;

  // z axis
  if ((t = a.GetLTV().z - b.GetLTV().z) > b.GetDepth() || -t > a.GetDepth()) 
    return false;

  // if not separated along any axis, AABBs are intersecting
  return true;
}


boolean TestAABBAABB(IAABBCR2D a, IAABBCR2D b) {
  // Compare the distance between centers with the sum of radii
  if (abs(a.GetCV().x - b.GetCV().x) > (a.GetRX() + b.GetRX())) return false;
  if (abs(a.GetCV().y - b.GetCV().y) > (a.GetRY() + b.GetRY())) return false;
  
  // if not separated along any axis, AABBs are intersecting
  return true;
}

boolean TestAABBAABB(IAABBCR3D a, IAABBCR3D b) {
  // Compare the distance between centers with the sum of radii
  if (abs(a.GetCV().x - b.GetCV().x) > (a.GetRX() + b.GetRX())) return false;
  if (abs(a.GetCV().y - b.GetCV().y) > (a.GetRY() + b.GetRY())) return false;
  if (abs(a.GetCV().z - b.GetCV().z) > (a.GetRZ() + b.GetRZ())) return false;
  
  // if not separated along any axis, AABBs are intersecting
  return true;
}

Util

  class MinMaxIndex {
    private int min;
    private int max;
  
    // Constructor
    MinMaxIndex(int min, int max) {
      this.min = min;
      this.max = max;
    }
  
    // Accessors
    int getMin() { return min; }
    void setMin(int min) { this.min = min; }
    int getMax() { return max; }
    void setMax(int max) { this.max = max; }
  }

  List<PVector> makeRandomCoords(int count)
  {
    var coords = new ArrayList<PVector>();
    for(int i = 0; i<count; i++)
    {
      var v = new PVector(random(width),random(height));
      coords.add(v);
    }    
    return coords;
  }
  List<PVector> makeRandomCoords(int count, float r)
  {
    var coords = new ArrayList<PVector>();
    var cv = new PVector(random(width),random(height));
    for(int i = 0; i<count; i++)
    {
      var v = new PVector(cv.x+random(-r,r),cv.y+random(-r,r));
      coords.add(v);
    }    
    return coords;
  }  

Hit Test

以下は現在選択中のBoundingBoxが、ほかのBoundingBoxに接触した時OKと表示する。

現在のコードではBoundingBoxのクリック時にCurrentObjectを設定し、Release時にCurrentObject=nullしているため、クリックおよびドラッグ時にしか判定しない。

void draw()
{
  background(255);
  noFill();
  strokeWeight(1);
  
  for(var obj : this.Objects)
  {
    if(obj instanceof IUpdatable)
    {
      ((IUpdatable)obj).update();
    }    
    if(obj instanceof IDrawable)
    {
      ((IDrawable)obj).draw();
    }
  }
  
     for(var obj : this.Objects)
     {
       if(this.CurrentObject!=null && obj!=this.CurrentObject)
       {        
         var bv = ((Object2D)obj).GetBV();
         var cbv = ((Object2D)this.CurrentObject).GetBV();
         
         if(bv instanceof IAABBMinMax2D && cbv instanceof IAABBMinMax2D)
         {
           if(TestAABBAABB((IAABBMinMax2D)bv, (IAABBMinMax2D)cbv))
           {
             fill(0);
             text("OK",0,0,20,20);
           }
         }
       }
     }  
}


この記事が気に入ったらサポートをしてみませんか?