Aplicación que muestra visualmente nueve métodos diferentes de generación de puntos aleatorios en un plano 2D. La ventana muestra una cuadrícula de 3x3, donde cada celda muestra una distribución distinta:
1- Uniforme: Puntos distribuidos equitativamente por toda la zona.
2- Normal (o Gaussiana): Puntos concentrados alrededor del centro de la zona, con densidad decreciente hacia los bordes.
3- Rejilla (Aleatoria): Puntos basados en una rejilla regular, pero con una pequeña desviación aleatoria (jitter) de su posición ideal.
4- Agrupada (Clusters): Puntos concentrados en varios "racimos" o grupos distribuidos aleatoriamente dentro de la zona.
5- Radial: Puntos distribuidos alrededor del centro, con mayor densidad cerca del centro y dispersándose hacia afuera.
6- Estratificada: La zona se divide en sub-celdas invisibles, y se coloca un punto aleatorio dentro de cada una, garantizando una cobertura muy uniforme.
7- Sesgo hacia Bordes: Puntos con mayor probabilidad de aparecer cerca de los bordes de la zona.
8- Sesgo Horizontal: Puntos distribuidos uniformemente en el eje horizontal, pero concentrados (según una curva normal) alrededor del centro vertical.
9- Sesgo Vertical: Puntos distribuidos uniformemente en el eje vertical, pero concentrados (según una curva normal) alrededor del centro horizontal.
Código Java (RandomnessVisualizer.java):
package randomnessvisualizer;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class RandomnessVisualizer {
private static final int WINDOW_WIDTH = 900;
private static final int WINDOW_HEIGHT = 900;
private static final int NUM_POINTS_PER_ZONE = 2000;
private static final Color LINE_COLOR = Color.BLACK;
private static final Color POINT_COLOR = Color.BLUE;
private static final int GRID_SIZE = 3;
private static final Color LABEL_COLOR = Color.BLACK;
private static final Font LABEL_FONT = new Font("SansSerif", Font.BOLD, 18);
private static final int LABEL_TOP_PADDING = 3;
private static final int LABEL_LEFT_PADDING = 5;
private static final double GAUSSIAN_STD_DEV_FACTOR = 1.0 / 6.0;
private static final double GRID_JITTER_FACTOR = 0.15;
private static final int NUM_CLUSTERS = 4;
private static final double CLUSTER_STD_DEV_FACTOR = 1.0 / 15.0;
private static final double RADIAL_CONCENTRATION = 0.5;
private static final double EDGE_BIAS_POWER = 2.0;
private static final double LINEAR_BIAS_STD_DEV_FACTOR = 1.0 / 8.0;
private static final String[] LABELS = {
"1. Uniforme", "2. Normal", "3. Rejilla",
"4. Clusters", "5. Radial", "6. Stratified",
"7. Edge Bias", "8. H. Bias", "9. V. Bias"
};
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Visualizador de Aleatoriedad (9 Zonas)");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
DrawingPanel drawingPanel = new DrawingPanel();
frame.add(drawingPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
static class DrawingPanel extends JPanel {
private final List<List<Point2D.Double>> zonePoints;
private final Random random;
public DrawingPanel() {
this.random = new Random();
this.zonePoints = new ArrayList<>(GRID_SIZE * GRID_SIZE);
for (int i = 0; i < GRID_SIZE * GRID_SIZE; i++) {
zonePoints.add(new ArrayList<>(NUM_POINTS_PER_ZONE));
}
generateAllZonePoints();
}
private void generateAllZonePoints() {
int zoneWidth = WINDOW_WIDTH / GRID_SIZE;
int zoneHeight = WINDOW_HEIGHT / GRID_SIZE;
for (int row = 0; row < GRID_SIZE; row++) {
for (int col = 0; col < GRID_SIZE; col++) {
int zoneIndex = row * GRID_SIZE + col;
int minX = col * zoneWidth;
int minY = row * zoneHeight;
List<Point2D.Double> currentZoneList = zonePoints.get(zoneIndex);
currentZoneList.clear();
switch (zoneIndex) {
case 0 -> generateUniformPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 1 -> generateNormalPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 2 -> generateGridPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 3 -> generateClusterPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 4 -> generateRadialPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 5 -> generateStratifiedPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 6 -> generateEdgeBiasPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 7 -> generateHorizontalBiasPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
case 8 -> generateVerticalBiasPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
default -> generateUniformPoints(currentZoneList, minX, minY, zoneWidth, zoneHeight);
}
}
}
}
private void generateUniformPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
for (int i = 0; i < NUM_POINTS_PER_ZONE; i++) {
double x = minX + random.nextDouble() * width;
double y = minY + random.nextDouble() * height;
points.add(new Point2D.Double(x, y));
}
}
private void generateNormalPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
double centerX = minX + width / 2.0;
double centerY = minY + height / 2.0;
double stdDevX = width * GAUSSIAN_STD_DEV_FACTOR;
double stdDevY = height * GAUSSIAN_STD_DEV_FACTOR;
int count = 0;
while (count < NUM_POINTS_PER_ZONE) {
double x = centerX + random.nextGaussian() * stdDevX;
double y = centerY + random.nextGaussian() * stdDevY;
if (x >= minX && x < (minX + width) && y >= minY && y < (minY + height)) {
points.add(new Point2D.Double(x, y));
count++;
}
}
}
private void generateGridPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
int numGridCells = (int) Math.ceil(Math.sqrt(NUM_POINTS_PER_ZONE));
double spacingX = width / numGridCells;
double spacingY = height / numGridCells;
double jitterX = spacingX * GRID_JITTER_FACTOR;
double jitterY = spacingY * GRID_JITTER_FACTOR;
int pointsGenerated = 0;
outerLoop:
for (int row = 0; row < numGridCells; row++) {
for (int col = 0; col < numGridCells; col++) {
if (pointsGenerated >= NUM_POINTS_PER_ZONE) {
break outerLoop;
}
double idealX = minX + (col + 0.5) * spacingX;
double idealY = minY + (row + 0.5) * spacingY;
double x = idealX + (random.nextDouble() - 0.5) * 2 * jitterX;
double y = idealY + (random.nextDouble() - 0.5) * 2 * jitterY;
x = Math.max(minX, Math.min(x, minX + width - 1));
y = Math.max(minY, Math.min(y, minY + height - 1));
points.add(new Point2D.Double(x, y));
pointsGenerated++;
}
}
while (points.size() < NUM_POINTS_PER_ZONE) {
double x = minX + random.nextDouble() * width;
double y = minY + random.nextDouble() * height;
points.add(new Point2D.Double(x, y));
}
while (points.size() > NUM_POINTS_PER_ZONE) {
points.remove(points.size() - 1);
}
}
private void generateClusterPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
List<Point2D.Double> clusterCenters = new ArrayList<>(NUM_CLUSTERS);
for (int i = 0; i < NUM_CLUSTERS; i++) {
double cX = minX + random.nextDouble() * width;
double cY = minY + random.nextDouble() * height;
clusterCenters.add(new Point2D.Double(cX, cY));
}
double stdDevX = width * CLUSTER_STD_DEV_FACTOR;
double stdDevY = height * CLUSTER_STD_DEV_FACTOR;
int count = 0;
while (count < NUM_POINTS_PER_ZONE) {
Point2D.Double center = clusterCenters.get(random.nextInt(clusterCenters.size()));
double x = center.x + random.nextGaussian() * stdDevX;
double y = center.y + random.nextGaussian() * stdDevY;
if (x >= minX && x < (minX + width) && y >= minY && y < (minY + height)) {
points.add(new Point2D.Double(x, y));
count++;
}
}
}
private void generateRadialPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
double centerX = minX + width / 2.0;
double centerY = minY + height / 2.0;
double maxRadius = Math.min(width, height) / 2.0;
int count = 0;
while (count < NUM_POINTS_PER_ZONE) {
double angle = random.nextDouble() * 2 * Math.PI;
double r = Math.pow(random.nextDouble(), 1.0 + RADIAL_CONCENTRATION) * maxRadius;
double x = centerX + r * Math.cos(angle);
double y = centerY + r * Math.sin(angle);
if (x >= minX && x < (minX + width) && y >= minY && y < (minY + height)) {
points.add(new Point2D.Double(x, y));
count++;
}
}
}
private void generateStratifiedPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
int numCellsPerSide = (int) Math.ceil(Math.sqrt(NUM_POINTS_PER_ZONE));
double cellWidth = width / numCellsPerSide;
double cellHeight = height / numCellsPerSide;
int count = 0;
outer:
for (int row = 0; row < numCellsPerSide; row++) {
for (int col = 0; col < numCellsPerSide; col++) {
if (count >= NUM_POINTS_PER_ZONE) {
break outer;
}
double cellMinX = minX + col * cellWidth;
double cellMinY = minY + row * cellHeight;
double x = cellMinX + random.nextDouble() * cellWidth;
double y = cellMinY + random.nextDouble() * cellHeight;
points.add(new Point2D.Double(x, y));
count++;
}
}
while (points.size() < NUM_POINTS_PER_ZONE) {
double x = minX + random.nextDouble() * width;
double y = minY + random.nextDouble() * height;
points.add(new Point2D.Double(x, y));
}
while (points.size() > NUM_POINTS_PER_ZONE) {
points.remove(points.size() - 1);
}
}
private void generateEdgeBiasPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
double centerX = minX + width / 2.0;
double centerY = minY + height / 2.0;
int count = 0;
while (count < NUM_POINTS_PER_ZONE) {
double x = minX + random.nextDouble() * width;
double y = minY + random.nextDouble() * height;
double normDistX = Math.abs(x - centerX) / (width / 2.0);
double normDistY = Math.abs(y - centerY) / (height / 2.0);
double normDist = Math.max(normDistX, normDistY);
if (random.nextDouble() < Math.pow(normDist, EDGE_BIAS_POWER)) {
points.add(new Point2D.Double(x, y));
count++;
}
}
}
private void generateHorizontalBiasPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
double centerY = minY + height / 2.0;
double stdDevY = height * LINEAR_BIAS_STD_DEV_FACTOR;
int count = 0;
while (count < NUM_POINTS_PER_ZONE) {
double x = minX + random.nextDouble() * width;
double y = centerY + random.nextGaussian() * stdDevY;
if (x >= minX && x < (minX + width) && y >= minY && y < (minY + height)) {
points.add(new Point2D.Double(x, y));
count++;
}
}
}
private void generateVerticalBiasPoints(List<Point2D.Double> points, double minX, double minY, double width, double height) {
double centerX = minX + width / 2.0;
double stdDevX = width * LINEAR_BIAS_STD_DEV_FACTOR;
int count = 0;
while (count < NUM_POINTS_PER_ZONE) {
double x = centerX + random.nextGaussian() * stdDevX;
double y = minY + random.nextDouble() * height;
if (x >= minX && x < (minX + width) && y >= minY && y < (minY + height)) {
points.add(new Point2D.Double(x, y));
count++;
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
int currentWidth = getWidth();
int currentHeight = getHeight();
int zoneWidth = currentWidth / GRID_SIZE;
int zoneHeight = currentHeight / GRID_SIZE;
currentWidth = zoneWidth * GRID_SIZE;
currentHeight = zoneHeight * GRID_SIZE;
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, currentWidth, currentHeight);
g2d.setColor(POINT_COLOR);
zonePoints.forEach(points -> {
drawPoints(g2d, points);
});
g2d.setColor(LINE_COLOR);
g2d.setStroke(new BasicStroke(1.5f));
for (int i = 1; i < GRID_SIZE; i++) {
g2d.drawLine(i * zoneWidth, 0, i * zoneWidth, currentHeight);
g2d.drawLine(0, i * zoneHeight, currentWidth, i * zoneHeight);
}
g2d.setStroke(new BasicStroke(1.0f));
g2d.setColor(LABEL_COLOR);
g2d.setFont(LABEL_FONT);
FontMetrics fm = g2d.getFontMetrics(LABEL_FONT);
for (int row = 0; row < GRID_SIZE; row++) {
for (int col = 0; col < GRID_SIZE; col++) {
int zoneIndex = row * GRID_SIZE + col;
int zoneX = col * zoneWidth;
int zoneY = row * zoneHeight;
int textX = zoneX + LABEL_LEFT_PADDING;
int textY = zoneY + LABEL_TOP_PADDING + fm.getAscent();
g2d.drawString(LABELS[zoneIndex], textX, textY);
}
}
}
private void drawPoints(Graphics2D g2d, List<Point2D.Double> points) {
points.stream().filter(p -> (p != null)).forEachOrdered(p -> {
g2d.drawLine((int) p.x, (int) p.y, (int) p.x, (int) p.y);
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(WINDOW_WIDTH, WINDOW_HEIGHT);
}
}
}
Resultado:
Código Java
Una forma sencilla y rápida de aprender JAVA, observando y deduciendo cómo se comporta el lenguaje a través de ejemplos prácticos.
Archivo del blog
viernes, 28 de marzo de 2025
Visualizando tipos de aleatoriedad de puntos.
Suscribirse a:
Entradas (Atom)
Con la tecnología de Blogger.