All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jfxtras.labs.util.Util Maven / Gradle / Ivy

There is a newer version: 9.0-r1
Show newest version
/**
 * Util.java
 *
 * Copyright (c) 2011-2015, JFXtras
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the organization nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL  BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package jfxtras.labs.util;

import java.util.Random;

import javafx.animation.Interpolator;
import javafx.beans.binding.DoubleBinding;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.geometry.Bounds;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.SnapshotParameters;
import javafx.scene.SnapshotParametersBuilder;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.image.Image;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.ImagePattern;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Paint;
import javafx.scene.paint.Stop;
import javafx.scene.shape.ArcType;
import javafx.scene.shape.Shape;
import jfxtras.labs.scene.control.gauge.GradientLookup;


/**
 * Created by
 * User: hansolo
 * Date: 27.01.12
 * Time: 15:35
 */
public class Util {

    /**************************************************************************
     *                                                                        *
     * Color related utilities                                                *
     *                                                                        *
     *************************************************************************/

    public static String colorToCssColor(final Color COLOR) {
        final StringBuilder CSS_COLOR = new StringBuilder(19);
        CSS_COLOR.append("rgba(");
        CSS_COLOR.append((int) (COLOR.getRed() * 255)).append(", ");
        CSS_COLOR.append((int) (COLOR.getGreen() * 255)).append(", ");
        CSS_COLOR.append((int) (COLOR.getBlue() * 255)).append(", ");
        CSS_COLOR.append(COLOR.getOpacity()).append(");");
        return CSS_COLOR.toString();
    }

    public static String colorToWebColor(final Color COLOR) {
        String red = Integer.toHexString((int)(COLOR.getRed() * 255));
        if (red.length() == 1) red = "0" + red;
        String green = Integer.toHexString((int)(COLOR.getGreen() * 255));
        if (green.length() == 1) green = "0" + green;
        String blue = Integer.toHexString((int)(COLOR.getBlue() * 255));
        if (blue.length() == 1) blue = "0" + blue;
        return "#" + red + green + blue;
    }

    /**
     * Converts hex color string to color
     * supported formats
     * 0xRRGGBB
     * 0xRRGGBBAA
     * #RRGGBB
     * #RRGGBBAA
     * RRGGBB
     * RRGGBBAA
     * @param COLOR
     * @return color given by hex string
     */
    public static Color webColorToColor(final String COLOR) {
        int    red;
        int    green;
        int    blue;
        double alpha = 1.0;
        if (COLOR.startsWith("0x")) {
            red   = Integer.valueOf(COLOR.substring(2, 4), 16);
            green = Integer.valueOf(COLOR.substring(4, 6), 16);
            blue  = Integer.valueOf(COLOR.substring(6, 8), 16);
            if (COLOR.length() > 8) {
                alpha = 1.0 / 255.0 * (double) (Integer.valueOf(COLOR.substring(8, 10), 16));
            }
        } else if (COLOR.startsWith("#")) {
            red   = Integer.valueOf(COLOR.substring(1, 3), 16);
            green = Integer.valueOf(COLOR.substring(3, 5), 16);
            blue  = Integer.valueOf(COLOR.substring(5, 7), 16);
            if (COLOR.length() > 7) {
                alpha = 1.0 / 255.0 * (double) (Integer.valueOf(COLOR.substring(7, 9), 16));
            }
        } else {
            red   = Integer.valueOf(COLOR.substring(0, 2), 16);
            green = Integer.valueOf(COLOR.substring(2, 4), 16);
            blue  = Integer.valueOf(COLOR.substring(4, 6), 16);
            if (COLOR.length() > 6) {
                alpha = 1.0 / 255.0 * (double) (Integer.valueOf(COLOR.substring(6, 8), 16));
            }
        }
        return Color.rgb(red, green, blue, alpha);
    }

    public static double[] HSLtoRGB(double hue, double saturation, double luminance) {
        double normalizedHue = ((hue % 360) + 360) %360;
        hue = normalizedHue / 360;
        double q;
        if (luminance < 0.5) {
            q = luminance * (1 + saturation);
        } else {
            q = (luminance + saturation) - (saturation * luminance);
        }
        double p     = 2 * luminance - q;
        double red   = Math.max(0, HueToRGB(p, q, hue + (1.0f / 3.0f)));
        double green = Math.max(0, HueToRGB(p, q, hue));
        double blue  = Math.max(0, HueToRGB(p, q, hue - (1.0f / 3.0f)));

        return new double[]{red, green, blue};
    }

    public static double[] RGBtoHSL(double red, double green, double blue) {
        //  Minimum and Maximum RGB values are used in the HSL calculations
        double min = Math.min(red, Math.min(green, blue));
        double max = Math.max(red, Math.max(green, blue));

        //  Calculate the Hue
        double hue = 0;
        if (max == min) {
            hue = 0;
        } else if (max == red) {
            hue = (( (green - blue) / (max - min) / 6.0) + 1) % 1;
        } else if (max == green) {
            hue = ( (blue - red) / (max - min) / 6.0) + 1.0 / 3.0;
        } else if (max == blue) {
            hue = ( (red - green) / (max - min) / 6.0) + 2.0 / 3.0;
        }
        hue *= 360;

        //  Calculate the Luminance
        double luminance = (max + min) / 2;

        //  Calculate the Saturation
        double saturation;
        if (Double.compare(max,min) == 0) {
            saturation = 0;
        } else if (luminance <= 0.5) {
            saturation = (max - min) / (max + min);
        } else {
            saturation = (max - min) / (2 - max - min);
        }

        return new double[]{ hue, saturation, luminance };
    }

    private static double HueToRGB(final double P, final double Q, double hue) {
        if (hue < 0) {
            hue += 1;
        }
        if (hue > 1 ) {
            hue -= 1;
        }
        if (6 * hue < 1) {
            return P + ((Q - P) * 6 * hue);
        }
        if (2 * hue < 1 ) {
            return  Q;
        }
        if (3 * hue < 2) {
            return P + ( (Q - P) * 6 * ((2.0 / 3.0) - hue) );
        }
        return P;
    }

    public static Color biLinearInterpolateColor(final Color COLOR_UL, final Color COLOR_UR, final Color COLOR_LL, final Color COLOR_LR, final float FRACTION_X, final float FRACTION_Y) {
        final Color INTERPOLATED_COLOR_X1 = (Color) Interpolator.LINEAR.interpolate(COLOR_UL, COLOR_UR, FRACTION_X);
        final Color INTERPOLATED_COLOR_X2 = (Color) Interpolator.LINEAR.interpolate(COLOR_LL, COLOR_LR, FRACTION_X);
        return (Color) Interpolator.LINEAR.interpolate(INTERPOLATED_COLOR_X1, INTERPOLATED_COLOR_X2, FRACTION_Y);
    }

    public static Color darker(final Color COLOR, final double FRACTION) {
        double red   = clamp(0, 1, COLOR.getRed() * (1.0 - FRACTION));
        double green = clamp(0, 1, COLOR.getGreen() * (1.0 - FRACTION));
        double blue  = clamp(0, 1, COLOR.getBlue() * (1.0 - FRACTION));
        return new Color(red, green, blue, COLOR.getOpacity());
    }

    public static Color brighter(final Color COLOR, final double FRACTION) {
        double red   = clamp(0, 1, COLOR.getRed() * (1.0 + FRACTION));
        double green = clamp(0, 1, COLOR.getGreen() * (1.0 + FRACTION));
        double blue  = clamp(0, 1, COLOR.getBlue() * (1.0 + FRACTION));
        return new Color(red, green, blue, COLOR.getOpacity());
    }

    public static double colorDistance(final Color COLOR1, final Color COLOR2) {
        final double DELTA_R = COLOR2.getRed() - COLOR1.getRed();
        final double DELTA_G = COLOR2.getGreen() - COLOR1.getGreen();
        final double DELTA_B = COLOR2.getBlue() - COLOR1.getBlue();
        return Math.sqrt(DELTA_R * DELTA_R + DELTA_G * DELTA_G + DELTA_B * DELTA_B);
    }

    public static boolean isDark(final Color COLOR) {
        final double DISTANCE_TO_WHITE = colorDistance(COLOR, Color.WHITE);
        final double DISTANCE_TO_BLACK = colorDistance(COLOR, Color.BLACK);
        return DISTANCE_TO_BLACK < DISTANCE_TO_WHITE;
    }

    public static boolean isBright(final Color COLOR) {
        return !isDark(COLOR);
    }


    /**************************************************************************
     *                                                                        *
     * Snapshot related utilities                                             *
     *                                                                        *
     *************************************************************************/
    private static final SnapshotParameters SNAPSHOT_PARAMETER = SnapshotParametersBuilder.create().fill(Color.TRANSPARENT).build();
    public static Image takeSnapshot(final Node NODE) {
        WritableImage img = new WritableImage((int) NODE.getLayoutBounds().getWidth(), (int) NODE.getLayoutBounds().getHeight());
        return NODE.snapshot(SNAPSHOT_PARAMETER, img);
    }


    /**************************************************************************
     *                                                                        *
     * Conical canvas gradient related utilities                              *
     *                                                                        *
     *************************************************************************/

    public static Canvas createConicalGradient(final Shape SHAPE, final Stop[] STOPS, final double ROTATION_OFFSET) {
                final Canvas CANVAS = new Canvas(SHAPE.getLayoutBounds().getWidth(), SHAPE.getLayoutBounds().getHeight());
                createConicalGradient(CANVAS, SHAPE, STOPS, ROTATION_OFFSET);
                return CANVAS;
            }

    public static void createConicalGradient(final Canvas CANVAS, final Shape SHAPE, final Stop[] STOPS, final double ROTATION_OFFSET) {
        // adjust size of canvas to size of shape if needed
        if (CANVAS.getLayoutBounds().getWidth() < SHAPE.getLayoutBounds().getWidth()) {
            CANVAS.setWidth(SHAPE.getLayoutBounds().getWidth());
        }
        if (CANVAS.getLayoutBounds().getHeight() < SHAPE.getLayoutBounds().getHeight()) {
            CANVAS.setHeight(SHAPE.getLayoutBounds().getHeight());
        }
        // create clip shape
        final Shape CLIP = SHAPE;
        CLIP.setTranslateX(-SHAPE.getLayoutBounds().getMinX());
        CLIP.setTranslateY(-SHAPE.getLayoutBounds().getMinY());
        // adjust position of canvas in relation to shape
        CANVAS.setLayoutX(SHAPE.getLayoutBounds().getMinX());
        CANVAS.setLayoutY(SHAPE.getLayoutBounds().getMinY());
        CANVAS.setClip(CLIP);
        // create the gradient with the given stops
        final GraphicsContext CTX          = CANVAS.getGraphicsContext2D();
        final Bounds          BOUNDS       = SHAPE.getLayoutBounds();
        final Point2D         CENTER       = new Point2D(BOUNDS.getWidth() / 2, BOUNDS.getHeight() / 2);
        final double          RADIUS       = Math.sqrt(BOUNDS.getWidth() * BOUNDS.getWidth() + BOUNDS.getHeight() * BOUNDS.getHeight()) / 2;
        final double          ANGLE_STEP   = 0.1;
        final GradientLookup COLOR_LOOKUP = new GradientLookup(STOPS);
        CTX.translate(CENTER.getX(), CENTER.getY());
        CTX.rotate(-90 + ROTATION_OFFSET);
        CTX.translate(-CENTER.getX(), -CENTER.getY());
        for (int i = 0, size = STOPS.length - 1; i < size; i++) {
            for (double angle = STOPS[i].getOffset() * 360; Double.compare(angle,STOPS[i + 1].getOffset() * 360) <= 0; angle += 0.1) {
                CTX.beginPath();
                CTX.moveTo(CENTER.getX() - RADIUS, CENTER.getY() - RADIUS);
                CTX.setFill(COLOR_LOOKUP.getColorAt(angle / 360));
                if (RADIUS > 0) {
                    CTX.fillArc(CENTER.getX() - RADIUS, CENTER.getY() - RADIUS, 2 * RADIUS, 2 * RADIUS, angle, ANGLE_STEP, ArcType.ROUND);
                } else {
                    CTX.moveTo(CENTER.getX() - RADIUS, CENTER.getY() - RADIUS);
                }
                CTX.fill();
            }
        }
    }


    /**************************************************************************
     *                                                                        *
     * Image pattern related utilities                                        *
     *                                                                        *
     *************************************************************************/

    public static ImagePattern createCarbonPattern() {
        final double WIDTH        = 12;
        final double HEIGHT       = 12;
        final Canvas CANVAS       = new Canvas(WIDTH, HEIGHT);
        final GraphicsContext CTX = CANVAS.getGraphicsContext2D();

        double offsetY = 0;

        // RULB
        CTX.beginPath();
        CTX.rect(0, 0, WIDTH * 0.5, HEIGHT * 0.5);
        CTX.closePath();

        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.5 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(35, 35, 35)),
                                       new Stop(1, Color.rgb(23, 23, 23))));
        CTX.fill();

        // RULF
        CTX.beginPath();
        CTX.rect(WIDTH * 0.083333, 0, WIDTH * 0.333333, HEIGHT * 0.416666);
        CTX.closePath();
        offsetY = 0;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.416666 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(38, 38, 38)),
                                       new Stop(1, Color.rgb(30, 30, 30))));
        CTX.fill();

        // RLRB
        CTX.beginPath();
        CTX.rect(WIDTH * 0.5, HEIGHT * 0.5, WIDTH * 0.5, HEIGHT * 0.5);
        CTX.closePath();
        offsetY = 0.5;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.5 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(35, 35, 35)),
                                       new Stop(1, Color.rgb(23, 23, 23))));
        CTX.fill();

        // RLRF
        CTX.beginPath();
        CTX.rect(WIDTH * 0.583333, HEIGHT * 0.5, WIDTH * 0.333333, HEIGHT * 0.416666);
        CTX.closePath();
        offsetY = 0.5;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.416666 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(38, 38, 38)),
                                       new Stop(1, Color.rgb(30, 30, 30))));
        CTX.fill();

        // RURB
        CTX.beginPath();
        CTX.rect(WIDTH * 0.5, 0, WIDTH * 0.5, HEIGHT * 0.5);
        CTX.closePath();
        offsetY = 0;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.5 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(48, 48, 48)),
                                       new Stop(1, Color.rgb(40, 40, 40))));
        CTX.fill();

        // RURF
        CTX.beginPath();
        CTX.rect(WIDTH * 0.583333, HEIGHT * 0.083333, WIDTH * 0.333333, HEIGHT * 0.416666);
        CTX.closePath();
        offsetY = 0.083333;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.416666 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(53, 53, 53)),
                                       new Stop(1, Color.rgb(45, 45, 45))));
        CTX.fill();

        // RLLB
        CTX.beginPath();
        CTX.rect(0, HEIGHT * 0.5, WIDTH * 0.5, HEIGHT * 0.5);
        CTX.closePath();
        offsetY = 0.5;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.5 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(48, 48, 48)),
                                       new Stop(1, Color.rgb(40, 40, 40))));
        CTX.fill();

        // RLLF
        CTX.beginPath();
        CTX.rect(WIDTH * 0.083333, HEIGHT * 0.583333, WIDTH * 0.333333, HEIGHT * 0.416666);
        CTX.closePath();
        offsetY = 0.583333;
        CTX.setFill(new LinearGradient(0, offsetY * HEIGHT,
                                       0, 0.416666 * HEIGHT + offsetY * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(53, 53, 53)),
                                       new Stop(1, Color.rgb(45, 45, 45))));
        CTX.fill();

        final Image PATTERN_IMAGE = CANVAS.snapshot(SNAPSHOT_PARAMETER, null);
        final ImagePattern PATTERN = new ImagePattern(PATTERN_IMAGE, 0, 0, WIDTH, HEIGHT, false);

        return PATTERN;
    }

    public static ImagePattern createPunchedSheetPattern(final Color TEXTURE_COLOR) {
        final double WIDTH = 15;
        final double HEIGHT = 15;
        final Canvas CANVAS = new Canvas(WIDTH, HEIGHT);
        final GraphicsContext CTX = CANVAS.getGraphicsContext2D();

        // BACK
        CTX.beginPath();
        CTX.rect(0, 0, WIDTH, HEIGHT);
        CTX.closePath();
        //CTX.setFill(Color.rgb(29, 33, 35));
        CTX.setFill(TEXTURE_COLOR);
        CTX.fill();

        // ULB
        CTX.beginPath();
        CTX.moveTo(0, HEIGHT * 0.266666);
        CTX.bezierCurveTo(0, HEIGHT * 0.4, WIDTH * 0.066666, HEIGHT * 0.466666, WIDTH * 0.2, HEIGHT * 0.466666);
        CTX.bezierCurveTo(WIDTH * 0.333333, HEIGHT * 0.466666, WIDTH * 0.4, HEIGHT * 0.4, WIDTH * 0.4, HEIGHT * 0.266666);
        CTX.bezierCurveTo(WIDTH * 0.4, HEIGHT * 0.133333, WIDTH * 0.333333, HEIGHT * 0.066666, WIDTH * 0.2, HEIGHT * 0.066666);
        CTX.bezierCurveTo(WIDTH * 0.066666, HEIGHT * 0.066666, 0, HEIGHT * 0.133333, 0, HEIGHT * 0.266666);
        CTX.closePath();
        CTX.setFill(new LinearGradient(0, 0.066666 * HEIGHT,
                                       0, 0.466666 * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(0, 0, 0)),
                                       new Stop(1, Color.rgb(68, 68, 68))));
        CTX.fill();

        // ULF
        CTX.beginPath();
        CTX.moveTo(0, HEIGHT * 0.2);
        CTX.bezierCurveTo(0, HEIGHT * 0.333333, WIDTH * 0.066666, HEIGHT * 0.4, WIDTH * 0.2, HEIGHT * 0.4);
        CTX.bezierCurveTo(WIDTH * 0.333333, HEIGHT * 0.4, WIDTH * 0.4, HEIGHT * 0.333333, WIDTH * 0.4, HEIGHT * 0.2);
        CTX.bezierCurveTo(WIDTH * 0.4, HEIGHT * 0.066666, WIDTH * 0.333333, 0, WIDTH * 0.2, 0);
        CTX.bezierCurveTo(WIDTH * 0.066666, 0, 0, HEIGHT * 0.066666, 0, HEIGHT * 0.2);
        CTX.closePath();
        CTX.setFill(TEXTURE_COLOR.darker().darker());
        CTX.fill();

        // LRB
        CTX.beginPath();
        CTX.moveTo(WIDTH * 0.466666, HEIGHT * 0.733333);
        CTX.bezierCurveTo(WIDTH * 0.466666, HEIGHT * 0.866666, WIDTH * 0.533333, HEIGHT * 0.933333, WIDTH * 0.666666, HEIGHT * 0.933333);
        CTX.bezierCurveTo(WIDTH * 0.8, HEIGHT * 0.933333, WIDTH * 0.866666, HEIGHT * 0.866666, WIDTH * 0.866666, HEIGHT * 0.733333);
        CTX.bezierCurveTo(WIDTH * 0.866666, HEIGHT * 0.6, WIDTH * 0.8, HEIGHT * 0.533333, WIDTH * 0.666666, HEIGHT * 0.533333);
        CTX.bezierCurveTo(WIDTH * 0.533333, HEIGHT * 0.533333, WIDTH * 0.466666, HEIGHT * 0.6, WIDTH * 0.466666, HEIGHT * 0.733333);
        CTX.closePath();
        CTX.setFill(new LinearGradient(0, 0.533333 * HEIGHT,
                                       0, 0.933333 * HEIGHT,
                                       false, CycleMethod.NO_CYCLE,
                                       new Stop(0, Color.rgb(0, 0, 0)),
                                       new Stop(1, Color.rgb(68, 68, 68))));
        CTX.fill();

        // LRF
        CTX.beginPath();
        CTX.moveTo(WIDTH * 0.466666, HEIGHT * 0.666666);
        CTX.bezierCurveTo(WIDTH * 0.466666, HEIGHT * 0.8, WIDTH * 0.533333, HEIGHT * 0.866666, WIDTH * 0.666666, HEIGHT * 0.866666);
        CTX.bezierCurveTo(WIDTH * 0.8, HEIGHT * 0.866666, WIDTH * 0.866666, HEIGHT * 0.8, WIDTH * 0.866666, HEIGHT * 0.666666);
        CTX.bezierCurveTo(WIDTH * 0.866666, HEIGHT * 0.533333, WIDTH * 0.8, HEIGHT * 0.466666, WIDTH * 0.666666, HEIGHT * 0.466666);
        CTX.bezierCurveTo(WIDTH * 0.533333, HEIGHT * 0.466666, WIDTH * 0.466666, HEIGHT * 0.533333, WIDTH * 0.466666, HEIGHT * 0.666666);
        CTX.closePath();
        CTX.setFill(TEXTURE_COLOR.darker().darker());
        CTX.fill();

        final Image PATTERN_IMAGE = CANVAS.snapshot(SNAPSHOT_PARAMETER, null);
        final ImagePattern PATTERN = new ImagePattern(PATTERN_IMAGE, 0, 0, WIDTH, HEIGHT, false);

        return PATTERN;
    }

    public static Image createNoiseImage(final double WIDTH, final double HEIGHT, final Color COLOR) {
        return createNoiseImage(WIDTH, HEIGHT, COLOR.darker(), COLOR.brighter(), 30);
    }

    public static Image createNoiseImage(final double WIDTH, final double HEIGHT, final Color DARK_COLOR, final Color BRIGHT_COLOR, final double ALPHA_VARIATION_IN_PERCENT) {
        if (WIDTH <= 0 || HEIGHT <= 0) {
            return null;
        }
        double alphaVariationInPercent      = clamp(0, 100, ALPHA_VARIATION_IN_PERCENT);
        final WritableImage IMAGE           = new WritableImage((int) WIDTH, (int) HEIGHT);
        final PixelWriter PIXEL_WRITER      = IMAGE.getPixelWriter();
        final Random        BW_RND          = new Random();
        final Random        ALPHA_RND       = new Random();
        final double        ALPHA_START     = alphaVariationInPercent / 100 / 2;
        final double        ALPHA_VARIATION = alphaVariationInPercent / 100;
        Color noiseColor;
        double noiseAlpha;
        for (int y = 0; y < HEIGHT; y++) {
            for (int x = 0; x < WIDTH; x++) {
                if (BW_RND.nextBoolean()) {
                    noiseColor = BRIGHT_COLOR;
                } else {
                    noiseColor = DARK_COLOR;
                }
                noiseAlpha = clamp(0, 1, ALPHA_START + ALPHA_RND.nextDouble() * ALPHA_VARIATION);
                PIXEL_WRITER.setColor(x, y, Color.color(noiseColor.getRed(), noiseColor.getGreen(), noiseColor.getBlue(), noiseAlpha));
            }
        }
        return IMAGE;
    }

    public static Paint applyNoisyBackground(final Shape SHAPE, final Color TEXTURE_COLOR) {
        final int           WIDTH           = (int) SHAPE.getLayoutBounds().getWidth();
        final int           HEIGHT          = (int) SHAPE.getLayoutBounds().getHeight();
        final WritableImage IMAGE           = new WritableImage(WIDTH, HEIGHT);
        final PixelWriter   PIXEL_WRITER    = IMAGE.getPixelWriter();
        final Random        BW_RND          = new Random();
        final Random        ALPHA_RND       = new Random();
        final double        ALPHA_START     = 0.045;
        final double        ALPHA_VARIATION = 0.09;
        Color  noiseColor;
        double noiseAlpha;
        for (int y = 0; y < HEIGHT; y++) {
            for (int x = 0; x < WIDTH; x++) {
                if (BW_RND.nextBoolean()) {
                    noiseColor = TEXTURE_COLOR.brighter();
                } else {
                    noiseColor = TEXTURE_COLOR.darker();
                }
                noiseAlpha = clamp(0, 1, ALPHA_START + ALPHA_RND.nextDouble() * ALPHA_VARIATION);
                PIXEL_WRITER.setColor(x, y, Color.color(noiseColor.getRed(), noiseColor.getGreen(), noiseColor.getBlue(), noiseAlpha));
            }
        }
		double x      = SHAPE.getLayoutBounds().getMinX();
		double y      = SHAPE.getLayoutBounds().getMinY();
		double width  = SHAPE.getLayoutBounds().getWidth();
	    double height = SHAPE.getLayoutBounds().getHeight();
		return new ImagePattern(IMAGE, x, y, width, height, false);
    }

    public static Image createBrushedMetalImage(final double WIDTH, final double HEIGHT, final Color TEXTURE_COLOR) {
        final BrushedMetalPaint PAINT = new BrushedMetalPaint(TEXTURE_COLOR);
        return PAINT.getImage(WIDTH, HEIGHT);
    }

    public static Paint applyBrushedMetalBackground(final Shape SHAPE, final Color TEXTURE_COLOR) {
        final BrushedMetalPaint PAINT = new BrushedMetalPaint(TEXTURE_COLOR);
        return PAINT.apply(SHAPE);
    }


    /**************************************************************************
     *                                                                        *
     * Misc utilities                                                         *
     *                                                                        *
     *************************************************************************/

    public static DoubleBinding getMaxSquareSizeBinding(final DoubleProperty WIDTH_PROPERTY, final DoubleProperty HEIGHT_PROPERTY) {
        final DoubleBinding MAX_SQUARE_SIZE = new DoubleBinding() {
            {
                super.bind(WIDTH_PROPERTY, HEIGHT_PROPERTY);
            }

            @Override protected double computeValue() {
                final double VALUE = WIDTH_PROPERTY.get() < HEIGHT_PROPERTY.get() ? WIDTH_PROPERTY.get() : HEIGHT_PROPERTY.get();
                return VALUE;
            }
        };
        return MAX_SQUARE_SIZE;
    }

    public static DoubleBinding getMaxSquareSizeBinding(final ReadOnlyDoubleProperty WIDTH_PROPERTY, final ReadOnlyDoubleProperty HEIGHT_PROPERTY) {
        final DoubleBinding MAX_SQUARE_SIZE = new DoubleBinding() {
            {
                super.bind(WIDTH_PROPERTY, HEIGHT_PROPERTY);
            }

            @Override protected double computeValue() {
                double VALUE = WIDTH_PROPERTY.get() < HEIGHT_PROPERTY.get() ? WIDTH_PROPERTY.get() : HEIGHT_PROPERTY.get();
                return VALUE;
            }
        };
        return MAX_SQUARE_SIZE;
    }

    public static double clamp(final double MIN, final double MAX, final double VALUE) {
        if (VALUE < MIN) return MIN;
        if (VALUE > MAX) return MAX;
        return VALUE;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy