Herramientas de usuario

Herramientas del sitio


numbers:graphics

¡Esta es una revisión vieja del documento!


Gráficos

Geometría

Problemas geométricos comunes

Ampliaremos la siguiente clase en Processing:

class Point {
  int x, y;
  Point (int x, int y) {
    this.x = x;
    this.y = y;
  }
  void draw () {
    point (x, y);
  }
}
class Line {
  Point p1, p2;
  Line (Point p1, Point p2) {
    this.p1 = new Point(p1.x, p1.y);
    this.p2 = new Point(p2.x, p2.y);
  }
}
  • Distancia entre dos puntos. En la clase Point:
  float distance (Point p) {
    // Resta y magnitud de dos vectores
    int subX = this.x - p.x;
    int subY = this.y - p.y;
    return sqrt(pow(subX,2) + pow(subY,2));
  }
  • Distancia entre un punto y una línea. En la clase Line:
 

Saber si dos líneas son paralelas
Saber si dos líneas son perpendiculares
Teniendo dos puntos y una línea, están los puntos al mismo lado de la línea?
Está la línea sobre dos puntos?
Un punto está en el ángulo de visión?

Transformaciones

Animaciones

Aceleración mediante vectores

Para los ejemplos se ha utilizado el lenguaje Processing y la clase PVector, utilizaremos tres vectores: uno para la posición, otro para la velocidad y otro para la aceleración.
La parte más importante del código es la clase Mover, esta tiene cuatro métodos: el constructor que inicializa los vectores e indica un máximo de velocidad, update que es con la que jugaremos para modificar la velocidad, display que mostrará la pelota según la posición actualy checkEdges que se encarga de controlar cuando la pelota sale de los bordes. La función setup inicializa la vista y el objeto Mover y la función update actualiza la vista.

Para crear una aceleración constante simplemente debemos ir sumando la aceleración a la velocidad y la velocidad a la posición. Limitaremos la velocidad a maxSpeed.

Mover mover;
 
void setup() {
  size(200,200);
  smooth();
  background(255);
  mover = new Mover(); 
}
 
void draw() {
  clean();
  mover.update();
  mover.checkEdges();
  mover.display(); 
}
 
void clean () {
  noStroke();
  fill(255,10);
  rect(0,0,width,height);
}
 
class Mover {
  PVector location;
  PVector velocity;
  PVector acceleration;
  float maxSpeed;
 
  Mover() {
    location = new PVector(width/2,height/2);
    velocity = new PVector(0, 0);
    acceleration = new PVector(-0.001,0.01);
    maxSpeed = 10.0;
  }
 
  void update() {
    velocity.add(acceleration);
    velocity.limit(maxSpeed);
    location.add(velocity);
  }
 
  void display() {
    stroke(0);
    fill(175);
    ellipse(location.x,location.y,16,16);
  }
 
  void checkEdges() {
    if (location.x > width) {
      location.x = 0;
    } else if (location.x < 0) {
      location.x = width;
    }
    if (location.y > height) {
      location.y = 0;
    } else if (location.y < 0) {
      location.y = height;
    }
  }
}

Crear una aceleración aleatoria es muy sencillo, en el update crearemos un nuevo vector con valores aleatorios y que asignaremos a la aceleración.

acceleration = new PVector(random(-1,1),random(-1,1));

Para realizar una aceleración condicionada por la distancia a la que se encuentra la pelota del mouse necesitamos un nuevo vector que nos indique la dirección hacia donde está el mouse, este nuevo vector será dir y lo creamos a partir de restar la posición del ratón y la posición de la bola. Luego normalizaremos el vector (esto nos creará un vector “proporcional” a la distancia) y lo multiplicaremos por un escalar (0.2 en nuestro caso).

maxSpeed = 4.0;
 
void update() {
  PVector mouse = new PVector(mouseX,mouseY);
  PVector dir = PVector.sub(mouse,location);
  dir.normalize();
  dir.mult(0.2);
  acceleration = dir;
 
  velocity.add(acceleration);
  velocity.limit(maxSpeed);
  location.add(velocity);
}

Interpolaciones

Si queremos mover la variable X de un punto pA a otro pB en N pasos tendremos la siguiente función (siendo i el paso actual): X = ((pB · (N - i)) + (pA · i)) / N

En Python con PyGame lo podríamos programar de la siguiente forma:

import pygame
from pygame.locals import *
import sys
 
def main ():
    i = 0
    pointA = 100
    pointB = 500
    x = pointA
    NumFrames = 100
 
    pygame.init()
    screen = pygame.display.set_mode((640,480))
    last_update = pygame.time.get_ticks()
    color = (0,0,0)
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                sys.exit()
        screen.fill(color)
        if (pygame.time.get_ticks() - last_update > 10):
            if (i> NumFrames):
                i = 0
                (pointA, pointB) = (pointB, pointA)
            last_update = pygame.time.get_ticks()
            x = ((pointB * i) + (pointA * (NumFrames - i))) / NumFrames
            i = i + 1
            pygame.draw.circle(screen, (0,0,255), (x, 200), 20)
            pygame.display.update()
 
if __name__ == '__main__':
    main()

O, el mismo código, con Processing:

int pointA = 100;
int pointB = 500;
float x = pointA;
float v = 0.0f;
int i = 0;
int numFrames = 100;
 
void setup ()
{
  size (640, 480);
}
 
void draw ()
{
  background(255);
  if (i > numFrames)
  {
    i = 0;
    int tmp = pointB;
    pointB = pointA;
    pointA = tmp;
  }
  x = ((pointB * i) + pointA * (numFrames - i)) / numFrames;
  i ++;
  ellipse(x, 200, 20, 20);
}

Lineal

Poniendolo de otra forma tenemos que la velocidad es: v = i / N y la función quedaría de la siguiente forma: x = ((pA · (1 - v)) + (pB · v)).
En python:

v = i / float(NumFrames)
x = (pointA * (1 - v)) + (pointB * v)

En processing:

v = i / (float)numFrames;
x = (pointA * (1 - v)) + (pointB * v);

Algoritmos

Perlin Noise

Es una función matemática que se usa para crear un gran número de vectores con el significado de intensidad y esta intensidad puede hacer referencia a varios conceptos que requieran aleatoriedad sin perder continuidad (degradados para texturas (de madera), posición de elementos en un mapa en un juego, creación de terrenos 3d…).

numbers/graphics.1270320911.txt.gz · Última modificación: 2020/05/09 09:24 (editor externo)