-->

Calculate ellipse size in relation to distance fro

2020-05-01 07:37发布

问题:

I want to achieve a slow fade in size on every collapse into itself. In other words, when the circle is at its biggest, the ellipses will be at the largest in size and conversely the opposite for the retraction. So far I am trying to achieve this affect by remapping the cSize from the distance of the center point, but somewhere along the way something is going wrong. At the moment I am getting a slow transition from small to large in ellipse size, but the inner ellipses are noticeably larger. I want an equal distribution of size amongst all ellipses in relation to center point distance.

I've simplified the code down to 4 ellipses rather than an array of rows of ellipses in order to hopefully simplify this example. This is done in the for (int x = -50; x <= 50; x+=100).

I've seen one or two examples that slightly does what I want, but is more or less static. This example is kind of similar because the ellipse size gets smaller or larger in relation to the mouse position

Distance2D

Here is an additional diagram of the grid of ellipses I am trying to create, In addition, I am trying to scale that "square grid" of ellipses by a center point.

Multiple ellipses + Scale by center

Any pointers?

float cSize;
float shrinkOrGrow;

void setup() {
    size(640, 640);
    noStroke();
    smooth();
    fill(255);
}

void draw() {
    background(#202020);
    translate(width/2, height/2);

    if (cSize > 10) {
      shrinkOrGrow = 0;
    } else if (cSize < 1 ) {
      shrinkOrGrow = 1;
}

    if (shrinkOrGrow == 1) {
      cSize += .1;
    } else if (shrinkOrGrow == 0) {
      cSize -= .1;
}
    for (int x = -50; x <= 50; x+=100) {
    for (int y = -50; y <= 50; y+=100) {
    float d = dist(x, y, 0, 0);    
    float fromCenter = map(cSize, 0, d, 1, 10);

  pushMatrix();
  translate(x, y);
  rotate(radians(d + frameCount));
  ellipse(x, y, fromCenter, fromCenter);
  popMatrix();
}
}
}

回答1:

The values you're passing into the map() function don't make a lot of sense to me:

float fromCenter = map(cSize, 0, d, 1, 100);

The cSize variable bounces from 1 to 10 independent of anything else. The d variable is the distance of each ellipse to the center of the circle, but that's going to be static for each one since you're using the rotate() function to "move" the circle, which never actually moves. That's based only on the frameCount variable, which you never use to calculate the size of your ellipses.

In other words, the position of the ellipses and their size are completely unrelated in your code.

You need to refactor your code so that the size is based on the distance. I see two main options for doing this:

Option 1: Right now you're moving the circles on screen using the translate() and rotate() functions. You could think of this as the camera moving, not the ellipses moving. So if you want to base the size of the ellipse on its distance from some point, you have to get the distance of the transformed point, not the original point.

Luckily, Processing gives you the screenX() and screenY() functions for figuring out where a point will be after you transform it.

Here's an example of how you might use it:

  for (int x = -50; x <= 50; x+=100) {
    for (int y = -50; y <= 50; y+=100) {
      pushMatrix();

      //transform the point
      //in other words, move the camera
      translate(x, y);
      rotate(radians(frameCount));

      //get the position of the transformed point on the screen
      float screenX = screenX(x, y);
      float screenY = screenY(x, y);

      //get the distance of that position from the center
      float distanceFromCenter = dist(screenX, screenY, width/2, height/2);

      //use that distance to create a diameter
      float diameter = 141 - distanceFromCenter;

      //draw the ellipse using that diameter
      ellipse(x, y, diameter, diameter);
      popMatrix();
    }
  }

Option 2: Stop using translate() and rotate(), and use the positions of the ellipses directly.

You might create a class that encapsulates everything you need to move and draw an ellipse. Then just create instances of that class and iterate over them. You'd need some basic trig to figure out the positions, but you could then use them directly.

Here's a little example of doing it that way:

ArrayList<RotatingEllipse> ellipses = new ArrayList<RotatingEllipse>();

void setup() {
  size(500, 500);
  ellipses.add(new RotatingEllipse(width*.25, height*.25));
  ellipses.add(new RotatingEllipse(width*.75, height*.25));
  ellipses.add(new RotatingEllipse(width*.75, height*.75));
  ellipses.add(new RotatingEllipse(width*.25, height*.75));
}

void draw() {
  background(0);

  for (RotatingEllipse e : ellipses) {
    e.stepAndDraw();
  }
}

void mouseClicked() {
  ellipses.add(new RotatingEllipse(mouseX, mouseY));
}

void mouseDragged() {
  ellipses.add(new RotatingEllipse(mouseX, mouseY));
}

class RotatingEllipse {

  float rotateAroundX;
  float rotateAroundY;
  float distanceFromRotatingPoint;
  float angle;

  public RotatingEllipse(float startX, float startY) {

    rotateAroundX = (width/2 + startX)/2;
    rotateAroundY = (height/2 + startY)/2;

    distanceFromRotatingPoint = dist(startX, startY, rotateAroundX, rotateAroundY);

    angle = atan2(startY-height/2, startX-width/2);
  }

  public void stepAndDraw() {

    angle += PI/64;

    float x = rotateAroundX + cos(angle)*distanceFromRotatingPoint;
    float y = rotateAroundY + sin(angle)*distanceFromRotatingPoint;

    float distance = dist(x, y, width/2, height/2);
    float diameter = 50*(500-distance)/500;

    ellipse(x, y, diameter, diameter);
  }
}

Try clicking or dragging in this example. User interaction makes more sense to me using this approach, but which option you choose really depends on what fits inside your head the best.



标签: processing