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

eu.hansolo.fx.countries.tools.Helper Maven / Gradle / Ivy

/*
 * Copyright (c) 2021 by Gerrit Grunwald
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package eu.hansolo.fx.countries.tools;

import eu.hansolo.fx.countries.Country;
import eu.hansolo.fx.countries.tools.Records.City;
import javafx.animation.Interpolator;
import javafx.scene.paint.Color;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;

import java.io.IOException;
import java.io.InputStream;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;
import java.util.NavigableMap;
import java.util.Optional;
import java.util.Properties;
import java.util.TreeMap;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public class Helper {
    private static final List cities   = new ArrayList<>();
    private static final List capitals = new ArrayList<>();

    public static final int clamp(final int min, final int max, final int value) {
        if (value < min) return min;
        if (value > max) return max;
        return value;
    }

    public static final long clamp(final long min, final long max, final long value) {
        if (value < min) return min;
        if (value > max) return max;
        return value;
    }

    public static final float clamp(final float min, final float max, final float value) {
        if (value < min) return min;
        if (value > max) return max;
        return value;
    }

    public static final double clamp(final double min, final double max, final double value) {
        if (value < min) return min;
        if (value > max) return max;
        return value;
    }

    public static final OperatingSystem getOperatingSystem() {
        String os = System.getProperty("os.name").toLowerCase();
        if (os.indexOf("win") >= 0)
            return OperatingSystem.WINDOWS;
        if (os.indexOf("mac") >= 0)
            return OperatingSystem.MACOS;
        if (os.indexOf("nix") >= 0 || os.indexOf("nux") >= 0)
            return OperatingSystem.LINUX;
        if (os.indexOf("sunos") >= 0) {
            return OperatingSystem.SOLARIS;
        }
        return OperatingSystem.NONE;
    }

    public static final List getCities() {
        if (cities.isEmpty()) {
            try {
                // city,city_ascii,lat,lng,country,iso2,iso3,admin_name,capital,population
                Path path = Paths.get(Helper.class.getResource("../cities.txt").toURI());
                Stream lines = Files.lines(path);
                lines.skip(1).forEach(line -> {
                    String[]          cityParts  = line.split(",");
                    String            name       = cityParts[0];
                    double            lat        = Double.parseDouble(cityParts[2]);
                    double            lon        = Double.parseDouble(cityParts[3]);
                    Optional countryOpt = Country.fromIso2(cityParts[5]);
                    Country           country    = countryOpt.isPresent() ? countryOpt.get() : null;
                    boolean           capital    = cityParts[8].equals("primary");
                    long              population = cityParts.length == 10 ? Long.parseLong(cityParts[9]) : -1;

                    if (null != country) { cities.add(new City(name, lat, lon, country, capital, population)); }
                });

                lines.close();
            } catch (URISyntaxException | IOException e) {
                System.out.println(e);
            }
        }
        return cities;
    }

    public static final List getCapitals() {
        if (capitals.isEmpty()) {
            capitals.addAll(getCities().stream().filter(city -> city.isCapital()).collect(Collectors.toList()));
        }
        return capitals;
    }

    public static final Map> createCountryPaths(final Resolution resolution) {
        final Properties                     properties   = readProperties(Resolution.HI_RES == resolution ? Constants.HIRES_PROPERTIES : Constants.LORES_PROPERTIES);
        final Map> countryPaths = new HashMap<>();
        properties.forEach((key, value) -> {
            final String            name     = key.toString();
            final List pathList = new ArrayList<>();
            for (String path : value.toString().split(";")) { pathList.add(new CountryPath(name, path)); }
            countryPaths.put(name, pathList);
        });
        return countryPaths;
    }

    public static final Map> createCountryPaths2(final Resolution resolution) {
        final Properties                      resolutionProperties = readProperties(Resolution.HI_RES == resolution ? Constants.HIRES_PROPERTIES : Constants.LORES_PROPERTIES);
        final Map> countryPaths         = new HashMap<>();
        resolutionProperties.forEach((key, value) -> {
            final String            iso2     = key.toString();
            final Optional country  = Country.fromIso2(key.toString());
            if (country.isEmpty()) { return; }
            final List pathList   = new ArrayList<>();
            for (String path : value.toString().split(";")) { pathList.add(new CountryPath(iso2, path)); }
            countryPaths.put(country.get(), pathList);
        });
        return countryPaths;
    }

    public static final String colorToWeb(final Color color) { return color.toString().replace("0x", "#").substring(0, 7); }

    public static final Color getColorAt(final LinearGradient gradient, final double fraction) {
        List stops     = gradient.getStops();
        double     frctn     = fraction < 0f ? 0f : (fraction > 1 ? 1 : fraction);
        Stop       lowerStop = new Stop(0.0, stops.get(0).getColor());
        Stop       upperStop = new Stop(1.0, stops.get(stops.size() - 1).getColor());

        for (Stop stop : stops) {
            double currentFraction = stop.getOffset();
            if (Double.compare(currentFraction, frctn) == 0) {
                return stop.getColor();
            } else if (Double.compare(currentFraction, frctn) < 0) {
                lowerStop = new Stop(currentFraction, stop.getColor());
            } else {
                upperStop = new Stop(currentFraction, stop.getColor());
                break;
            }
        }

        double interpolationFraction = (frctn - lowerStop.getOffset()) / (upperStop.getOffset() - lowerStop.getOffset());
        return (Color) Interpolator.LINEAR.interpolate(lowerStop.getColor(), upperStop.getColor(), interpolationFraction);
    }

    public static final double distance(final double x1, final double y1, final double x2, final double y2) {
        return Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
    }

    public static final double bearing(final Point p1, final Point p2) {
        return bearing(p1.getX(), p1.getY(), p2.getX(), p2.getY());
    }
    public static final double bearing(final double x1, final double y1, final double x2, final double y2) {
        double bearing = Math.toDegrees(Math.atan2(y2 - y1, x2 - x1)) + 90;
        if (bearing < 0) { bearing += 360.0; }
        return bearing;
    }

    public static final int getMinutes(final double decimalDegree) { return (int) ((decimalDegree - ((int) decimalDegree)) * 60); }
    public static final double getSeconds(final double decimalDegree) { return (((decimalDegree - ((int) decimalDegree)) * 60) - getMinutes(decimalDegree)) * 60; }

    public static final double getDecimalDeg(final int degrees, final int minutes, final double seconds) {
        return (((seconds / 60) + minutes) / 60) + degrees;
    }

    public static final Point latLonToXY(final Point latlon) {
        return latLonToXY(latlon, Constants.MAP_OFFSET_X, Constants.MAP_OFFSET_Y, Constants.MAP_WIDTH, Constants.MAP_HEIGHT);
    }
    public static final Point latLonToXY(final Point latlon, final double mapOffsetX, final double mapOffsetY, final double mapWidth, final double mapHeight) {
        final double[] xy = latLonToXY(latlon.getY(), latlon.getX(), mapOffsetX, mapOffsetY, mapWidth, mapHeight);
        return new Point(xy[0], xy[1]);
    }
    public static final double[] latLonToXY(final double latitude, final double longitude, final double mapOffsetX, final double mapOffsetY, final double mapWidth, final double mapHeight) {
        final double x = (longitude + 180) * (mapWidth / 360) + mapOffsetX;
        final double y = (mapHeight / 2) - (mapWidth * (Math.log(Math.tan((Math.PI / 4) + (Math.toRadians(latitude) / 2)))) / (2 * Math.PI)) + mapOffsetY;
        return new double[]{ x, y };
    }

    public static final Point xyToLatLon(final Point xy) {
        return xyToLatLon(xy, Constants.MAP_OFFSET_X, Constants.MAP_OFFSET_Y, Constants.MAP_WIDTH, Constants.MAP_HEIGHT);
    }
    public static final Point xyToLatLon(final Point xy, final double mapOffsetX, final double mapOffsetY, final double mapWidth, final double mapHeight) {
        final double[] ll = xyToLatLon(xy.getY(), xy.getX(), mapOffsetX, mapOffsetY, mapWidth, mapHeight);
        return new Point(ll[0], ll[1]);
    }
    public static final double[] xyToLatLon(final double x, final double y, final double mapOffsetX, final double mapOffsetY, final double mapWidth, final double mapHeight) {
        final double longitude = ((x - mapOffsetX) * 360) / mapWidth - 180;
        final double latitude  = Math.toDegrees(-(Math.atan(Math.exp((((y - mapOffsetY) * 2 - mapHeight) * Math.PI) / mapWidth)) * 4 - Math.PI) / 2);
        return new double[]{ latitude, longitude };
    }

    public static final Properties readProperties(final String filename) {
        final ClassLoader loader     = Thread.currentThread().getContextClassLoader();
        final Properties  properties = new Properties();
        try(InputStream resourceStream = loader.getResourceAsStream(filename)) {
            properties.load(resourceStream);
        } catch (IOException exception) {
        }
        return properties;
    }

    private static final NavigableMap SUFFIXES = new TreeMap<>(Map.of(1_000L, "k",
                                                                                    1_000_000L, "M",
                                                                                    1_000_000_000L, "G",
                                                                                    1_000_000_000_000L, "T",
                                                                                    1_000_000_000_000_000L, "P",
                                                                                    1_000_000_000_000_000_000L, "E"));
    public static final String shortenNumber(final long value) {
        return shortenNumber(value, Locale.US);
    }
    public static final String shortenNumber(final long value, final Locale locale) {
        //Long.MIN_VALUE == -Long.MIN_VALUE so we need an adjustment here
        if (value == Long.MIN_VALUE) { return shortenNumber(Long.MIN_VALUE + 1, locale); }
        if (value < 0)               { return "-" + shortenNumber(-value, locale); }
        if (value < 1000)            { return Long.toString(value); }

        final Entry entry    = SUFFIXES.floorEntry(value);
        final Long                divideBy = entry.getKey();
        final String                 suffix     = entry.getValue();
        final long                   truncated  = value / (divideBy / 10);
        final boolean                hasDecimal = truncated < 100 && (truncated / 10d) != (truncated / 10);
        final java.text.NumberFormat formatter  = java.text.NumberFormat.getNumberInstance(locale);
        formatter.setMinimumFractionDigits(1);
        formatter.setMaximumFractionDigits(1);
        return hasDecimal ? formatter.format(truncated / 10d) + suffix : (truncated / 10) + suffix;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy