Example17.java

/*
 *                      ..::jDrawingLib::..
 *
 * Copyright (C) Federico Vera 2012 - 2023 <[email protected]>
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 3 of the License, or any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.dkt.graphics.extras.examples;

import com.dkt.graphics.canvas.Canvas;
import com.dkt.graphics.canvas.CanvasFrame;
import com.dkt.graphics.elements.GCircle;
import com.dkt.graphics.elements.GLine;
import com.dkt.graphics.elements.GPoint;
import com.dkt.graphics.elements.GString;
import com.dkt.graphics.utils.GuiUtils;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.Timer;

/**
 *
 * @author Federico Vera {@literal<[email protected]>}
 */
public class Example17  implements IExample {
    private final GString S1 = new GString(-240 , 230, "The theory behind this can be found at:");
    private final GString S2 = new GString(-240 , 245, "http://www.jasondavies.com/random-polygon-ellipse/");
    
    @Override
    public void run() {
        final CanvasFrame cf = new CanvasFrame(getName());
        cf.setVisible(true);
        cf.setSize(600, 600);

        GuiUtils.centerFrame(cf);

        final Canvas canvas = cf.getCanvas();
        canvas.setDrawableSize(500, 500);
        canvas.setCenterBounds(true);
        canvas.setCenterOrigin(true);
        canvas.setUseAntiAliasing(true);
        canvas.setAutoRepaint(true);
        canvas.setRepaintDelay(25);

        final int nPoints = 35;
        final GPoint[] points = new GPoint[nPoints];

        final Random rand = new Random();
        for (int i = 0; i < nPoints; i++) {
            final int x = rand.nextInt(500) - 250;
            final int y = rand.nextInt(500) - 250;
            points[i] = new GPoint(x, y);
        }

        final Timer timer = new Timer(200, null);
        timer.addActionListener(new ActionListener() {
            private GPoint[] pts = points;
            private int a;
            //If you set this to true you'll see all the transformations
            //otherwise it will skip one frame and the animation will be
            //smoother
            private final boolean alternate = true;
            @Override
            public void actionPerformed(ActionEvent evt) {
                if (alternate && a % 2 == 0) {
                    canvas.removeAll();
                }

                GLine[] lines = getLines(pts);

                if (alternate && a % 2 == 0) {
                    for (GLine line : lines) {
                        canvas.add(line);
                    }
                    showPointsAsCircles(canvas, pts, Color.WHITE);
                }

                pts = new GPoint[lines.length];

                int i = 0;
                for (GLine line : lines) {
                    pts[i++] = line.getMiddlePoint();
                }

                if (alternate && a % 2 == 0) {
                    canvas.add(S1);
                    canvas.add(S2);
                }

                transform(pts);
                a++;
            }
        });

        timer.setDelay(50);
        timer.setRepeats(true);
        timer.start();
    }

    @Override
    public String getName() {
        return "Random point elipse";
    }

    private void showPointsAsCircles(Canvas canvas, GPoint[] points, Color col) {
        for (GPoint p : points) {
            GCircle c = new GCircle(p.x(), p.y(), 3);
            c.setFillPaint(col);
            c.setFill(true);
            canvas.add(c);
        }
    }

    private GLine[] getLines(GPoint[] points) {
        GLine[] lines = new GLine[points.length];

        for (int i = 0; i < points.length - 1; i++) {
            lines[i] = new GLine(points[i], points[i + 1]);
        }

        lines[points.length - 1] = new GLine(points[0], points[points.length - 1]);
        return lines;
    }

    private void transform(GPoint[] pts) {
        //We avoid using an affine transform since it also increases the size
        //of the stroke
        int l =  250;
        int r = -250;
        int u =  250;
        int d = -250;

        for (final GPoint p : pts) {
            l = Math.min(l, p.x());
            r = Math.max(r, p.x());
            u = Math.min(u, p.y());
            d = Math.max(d, p.y());
        }

        final double sx = 500. / (r - l);
        final double sy = 500. / (d - u);

        int i = 0;
        for (final GPoint p : pts) {
            final int x = (int)(p.x() * sx) - r + (r - l) / 2;
            final int y = (int)(p.y() * sy) - d + (d - u) / 2;

            pts[i++] = new GPoint(x, y);
        }
    }
}