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

org.nuiton.jaxx.widgets.gis.DmsCoordinate Maven / Gradle / Ivy

There is a newer version: 3.0-alpha-6
Show newest version
package org.nuiton.jaxx.widgets.gis;

/*
 * #%L
 * JAXX :: Widgets
 * %%
 * Copyright (C) 2008 - 2014 Code Lutin, Tony Chemit
 * %%
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as 
 * published by the Free Software Foundation, either version 3 of the 
 * License, or (at your option) 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 Lesser Public License for more details.
 * 
 * You should have received a copy of the GNU General Lesser Public 
 * License along with this program.  If not, see
 * .
 * #L%
 */

import org.jdesktop.beans.AbstractSerializableBean;

import java.util.regex.Pattern;

/**
 * Geo coordinate in degree, minute, second format.
 *
 * Created on 10/23/13.
 *
 * @author Tony Chemit - [email protected]
 * @since 2.12
 */
public class DmsCoordinate extends AbstractSerializableBean {

    public static final String COORDINATE_STRING_PATTERN = "%s%s°%s'%s''";

    public static final Pattern COORDINATE_PATTERN =
            Pattern.compile("(.*)°(.*)'(.*)''");

    private static final long serialVersionUID = 1L;

    public static final String PROPERTY_SIGN = "sign";

    public static final String PROPERTY_DEGREE = "degree";

    public static final String PROPERTY_MINUTE = "minute";

    public static final String PROPERTY_SECOND = "second";

    protected boolean sign;

    protected Integer degree;

    protected Integer minute;

    protected Integer second;

    public static DmsCoordinate empty() {
        return new DmsCoordinate();
    }

    /**
     * Methode statique de fabrique de position a partir d'un autre {@link DmsCoordinate}.
     *
     * Note : Si la valeur vaut null, alors on
     * reinitialise les composants de la position a null et la
     * methode {@link #isNull()} vaudra alors {@code true}.
     *
     * @param decimal la valeur au format decimal
     * @return une nouvelle instance de position convertie
     */
    public static DmsCoordinate valueOf(DmsCoordinate decimal) {
        DmsCoordinate r = new DmsCoordinate();
        if (decimal != null) {
            r.setSign(decimal.isSign());
            r.setDegree(decimal.getDegree());
            r.setMinute(decimal.getMinute());
            r.setSecond(decimal.getSecond());
        }
        return r;
    }

    /**
     * Methode statique de fabrique de position a partir d'une valeur du format
     * decimal.
     *
     * Note : Si la valeur (au format decimal) vaut null, alors on
     * reinitialise les composants de la position a null et la
     * methode {@link #isNull()} vaudra alors {@code true}.
     *
     * @param decimal la valeur au format decimal
     * @return une nouvelle instance de position convertie
     */
    public static DmsCoordinate valueOf(Float decimal) {
        DmsCoordinate r = new DmsCoordinate();
        r.fromDecimal(decimal);
        return r;
    }

    /**
     * Methode statique de fabrique de position a partir d'une valeur du format
     * degre-minute-seconde.
     *
     * @param d la valeur des degres
     * @param m la valeur des minutes
     * @param s la valeur des secondes
     * @return une nouvelle instance de position convertie
     */
    public static DmsCoordinate valueOf(boolean sign, Integer d, Integer m, Integer s) {
        DmsCoordinate r = new DmsCoordinate();
        r.setSign(sign);
        r.setDegree(d);
        r.setMinute(m);
        r.setSecond(s);
        return r;
    }

    public boolean isSign() {
        return sign;
    }

    public Integer getDegree() {
        return degree;
    }

    public Integer getMinute() {
        return minute;
    }

    public Integer getSecond() {
        return second;
    }

    public void setSign(boolean sign) {
        Object oldValue = isSign();
        this.sign = sign;
        firePropertyChange(PROPERTY_SIGN, oldValue, sign);
    }

    public void setDegree(Integer degree) {
        Object oldValue = getDegree();
        this.degree = degree;
        firePropertyChange(PROPERTY_DEGREE, oldValue, degree);
    }

    public void setMinute(Integer minute) {
        Object oldValue = getMinute();
        this.minute = minute;
        firePropertyChange(PROPERTY_MINUTE, oldValue, minute);
    }

    public void setSecond(Integer second) {
        Object oldValue = getSecond();
        this.second = second;
        firePropertyChange(PROPERTY_SECOND, oldValue, second);
    }

    public boolean isDegreeNull() {
        return degree == null || degree == 0;
    }

    public boolean isMinuteNull() {
        return minute == null || minute == 0;
    }

    public boolean isSecondNull() {
        return second == null || second == 0;
    }

    /**
     * @return {@code true} si aucune composante n'est renseignée,
     * {@code false} autrement.
     */
    public boolean isNull() {
        return degree == null && minute == null && second == null;
    }

    /**
     * Mets a jour les composants de la position a partir d'une valeur decimal.
     *
     * Note : Si la valeur (au format decimal) vaut null, alors on
     * reinitialise les composants de la position a null et la
     * methode {@link #isNull()} vaudra alors {@code true}.
     *
     * @param decimal la valeur decimale a convertir (qui peut etre nulle).
     */
    public void fromDecimal(Float decimal) {
        Integer d = null;
        Integer m = null;
        Integer s = null;
        boolean si = false;
        if (decimal != null) {
            si = decimal < 0;

            decimal = Math.abs(decimal);
            int remain = 0;

            d = (int) (Math.round(decimal + 0.5) - 1);
            m = 0;
            s = 0;
            decimal = 60.0f * (decimal - d);
            if (decimal > 0) {
                m = (int) (Math.round(decimal + 0.5) - 1);
                decimal = 60 * (decimal - m);
                if (decimal > 0) {
                    s = (int) (Math.round(decimal + 0.5) - 1);
                    remain = (int) (10 * (decimal - s));
                }
            }
            if (remain > 9) {
                s++;
            }
            if (s == 60) {
                m++;
                s = 0;
            }
            if (m == 60) {
                d++;
                m = 0;
            }
        }

        degree = d;
        minute = m;
        second = s;
        sign = si;

        if (decimal != null) {
            removeTrailingZero();
        }
    }

    public Float toDecimal() {
        if (isNull()) {
            return null;
        }
        Integer d = getNotNullDegree();
        Integer m = getNotNullMinute();

        Integer s = getNotNullSecond();

        Float result = Float.valueOf(d);

        if (m > 0) {
            result += (float) m / 60;
            if (s == 0) {
                result += 0.5f / 3600;
            }
        }
        if (s > 0) {
            result += ((float) s + 0.5f) / 3600;
        }

        if (sign) {
            result *= -1;
        }
        result = CoordinateHelper.roundToFourDecimals(result);
        return result;
    }

    public DmsCoordinate addTrailingZero() {
        if (degree == null) {
            degree = 0;
        }
        if (minute == null) {
            minute = 0;
        }
        if (second == null) {
            second = 0;
        }
        return this;
    }

    public DmsCoordinate removeTrailingZero() {
        if (degree != null && degree == 0) {
            degree = null;
        }
        if (minute != null && minute == 0) {
            minute = null;
        }
        if (second != null && second == 0) {
            second = null;
        }
        return this;
    }

    public Integer getSignedDegree() {
        Integer result = null;
        if (!isDegreeNull()) {
            result = degree;
            if (isSign()) {
                result *= -1;
            }
        }
        return result;
    }

    public int getNotNullDegree() {
        return isDegreeNull() ? 0 : degree;
    }

    public int getNotNullMinute() {
        return isMinuteNull() ? 0 : minute;
    }


    public int getNotNullSecond() {
        return isSecondNull() ? 0 : second;
    }

    public boolean isLatitudeDegreeValid() {
        return isDegreeValid(false);
    }

    public boolean isLongitudeDegreeValid() {
        return isDegreeValid(true);
    }

    public boolean isMinuteValid() {
        boolean result = true;
        if (!isMinuteNull()) {
            if (60 == minute) {

                // check minute and second are null
                result = isSecondNull();
            } else {
                result = 0 <= minute && minute < 60;
            }
        }
        return result;
    }

    public boolean isSecondValid() {
        return isSecondNull() || (0 <= second && second < 60);
    }

    @Override
    public String toString() {
        return "DmsCoordinateComponent{" +
               "sign=" + sign +
               ", degree=" + degree +
               ", minute=" + minute +
               ", second=" + second +
               '}';
    }

    protected boolean isDegreeValid(boolean longitude) {
        boolean result = true;
        if (!isDegreeNull()) {
            int bound = longitude ? 180 : 90;
            if (bound == degree) {

                // check minute and second are null
                result = isMinuteNull() && isSecondNull();
            } else {
                result = degree < bound;
            }
        }
        return result;
    }

    public void reset() {
        degree=null;
        minute=null;
        second=null;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy