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.

 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:



Con la tecnología de Blogger.