Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
435 views
in Technique[技术] by (71.8m points)

processing - How can I make spheres with certain amount of distance between each of them?

Hi everytime I press keys, I want to reposition my objects(spheres) in random position(x,y,z). but I want them to be always apart from each other. How can I achieve it? sorry If my question was unclear. I am not english speaker. I try to give more details if you want.

Mover movers[] = new Mover[1000];
Attractor attractors[]=new Attractor[5];

void setup() {
  size(300, 400, P3D);
  for (int i=0; i<attractors.length; i++) {
    attractors[i] = new Attractor(random(0.1, 2), random(0, width), random(0, height), random(-100, 100));
  }
}

void draw() {
  background(255);
  for (int i=0; i<attractors.length; i++) {
    attractors[i].display();
  }
  
}

void keyPressed() {
for (int i=0; i<attractors.length; i++) {
    for (int j=0; j<attractors.length; j++) {
     PVector f = PVector.sub(attractors[i].loc,attractors[j].loc);
    float distance = f.mag();
      if (i!=j) {
        while (true) {
          attractors[j].loc.x = random(0, width);
          attractors[j].loc.y = random(0, height);
          attractors[j].loc.z = 0;
          if (distance>=50) {
            break;
          }    
        }

        println(distance);
      }
    }
  
  }
}

I have class called attractor, and it has loc(location) field. and display function which displays spheres. The code above is failed code. '''


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Poisson-Disc Sampling is a go-to technique for this problem.

Poisson-disc sampling produces points that are tightly-packed, but no closer to each other than a specified minimum distance, resulting in a more natural pattern.

Processing Example:

This is an example of the technique in 2D (distributing circles); the technique can be extended to 3D (for sphere distribution), though it would be a little more involved.

enter image description here

import java.util.Vector;
import java.util.LinkedList;

PoissonDistribution points = new PoissonDistribution();

int minimumDistance = 50;

void setup() {
  size(800, 800);
  fill(200, 40, 80);
  points.generate(0, 0, width, height, minimumDistance, 15);
}

void draw() {
  background(255);
  for (PVector coord : points.getPoints()) {
    ellipse(coord.x, coord.y, minimumDistance - 10, minimumDistance - 10);
  }
}

void keyPressed() {
  points.generate(0, 0, width, height, minimumDistance, 15);
}

class PoissonDistribution
{
  /** From "Fast Poisson Disk Sampling in Arbitrary Dimensions"
   * by Robert Bridson
   * http://www.cs.ubc.ca/~rbridson/docs/bridson-siggraph07-poissondisk.pdf
   **/

  PoissonDistribution()
  {
    _points = new Vector<PVector>();
  }

  Vector<PVector> getPoints() { 
    return _points;
  }

  Vector<PVector> generate(float xmin, float ymin, float xmax, float ymax, float minDist, int rejectionLimit)
  {
    _xmin = xmin; 
    _xmax = xmax; 
    _ymin = ymin; 
    _ymax = ymax;
    _cellSize = minDist / sqrt(2);
    _gridWidth = ceil((xmax-xmin) / _cellSize);
    _gridHeight = ceil((ymax-ymin) / _cellSize);
    int s = _gridWidth * _gridHeight;
    _grid = new ArrayList<Vector<PVector>>();
    for (int i=0; i<s; i++)
      _grid.add(new Vector<PVector>());

    _points.clear();
    LinkedList<PVector> processList = new LinkedList<PVector>();

    PVector p = new PVector(random(_xmin, _xmax), random(_ymin, _ymax));
    processList.add(p);
    _points.add(p);
    addToGrid(p);

    while (processList.size() > 0)
    {
      int i = floor(random(processList.size()));
      p = processList.get(i);
      processList.remove(i);
      for (i=0; i<rejectionLimit; i++)
      {
        PVector n = createRandomPointAround(p, minDist, minDist*2);
        if (insideBoundaries(n) && testGrid(n, minDist)) {
          processList.add(n);
          _points.add(n);
          addToGrid(n);
        }
      }
    }

    return _points;
  }

  private boolean insideBoundaries(PVector p)
  {
    return (p.x >= _xmin && p.x < _xmax && p.y >= _ymin && p.y < _ymax);
  }

  private PVector createRandomPointAround(PVector p, float minDist, float maxDist)
  {
    float a = random(2*PI);
    float r = random(minDist, maxDist);
    return new PVector(p.x + r * cos(a), p.y + r * sin(a));
  }

  // return true if there are no points inside the circle of minDist radius around p
  private boolean testGrid(PVector p, float minDist)
  {
    int minX = floor(max(0, (p.x - minDist - _xmin) / _cellSize));
    int maxX = ceil(min(_gridWidth - 1, (p.x + minDist - _xmin) / _cellSize));
    int minY = floor(max(0, (p.y - minDist - _ymin) / _cellSize));
    int maxY = ceil(min(_gridHeight - 1, (p.y + minDist - _ymin) / _cellSize));

    for (int y=minY; y<=maxY; y++) {
      for (int x=minX; x<=maxX; x++) {
        Vector<PVector> cell = _grid.get(y * _gridWidth + x);
        for (PVector t : cell)
          if (dist(p.x, p.y, t.x, t.y) <= minDist)
            return false;
      }
    }

    return true;
  }

  private void addToGrid(PVector p)
  {
    _grid.get(index(p.x, p.y)).add(p);
  }

  protected int index(float x, float y)
  {
    int gx = floor((x - _xmin) / _cellSize);
    int gy = floor((y - _ymin) / _cellSize);
    return gy * _gridWidth + gx;
  }

  private ArrayList<Vector<PVector>> _grid;
  private float _cellSize;
  private int _gridWidth, _gridHeight;
  private float _xmin, _xmax, _ymin, _ymax;
  private Vector<PVector> _points;
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to MLink Developer Q&A Community for programmer and developer-Open, Learning and Share
...