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

org.dstadler.ctw.utils.UTMRefWithHash Maven / Gradle / Ivy

package org.dstadler.ctw.utils;

import static org.dstadler.ctw.utils.Constants.SQUARE_SIZE;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import org.apache.commons.io.FileUtils;

import uk.me.jstott.jcoord.LatLng;
import uk.me.jstott.jcoord.NotDefinedOnUTMGridException;
import uk.me.jstott.jcoord.UTMRef;

/**
 * Helper class to provide an extension to {@link uk.me.jstott.jcoord.UTMRef}
 * which can be used in HashMap/HashSet.
 *
 * It also provides support for computing the 1km-"square" into which given
 * {@link uk.me.jstott.jcoord.LatLng} coordinates fall into.
 */
public class UTMRefWithHash extends UTMRef implements BaseTile {
	// numerical value between 1 and 60
	private static final String LNG_ZONE_PATTERN = "(\\d{1,2})";
	// Uppercase letter between C and X without I and O
	private static final String LAT_ZONE_PATTERN = "([C-HJ-NP-X])";
	// number of meters
	private static final String EASTING_NORTHING_PATTERN = "(\\d+(?:\\.\\d+)?)";

	private static final Pattern UTMREF_PATTERN = Pattern.compile(
			LNG_ZONE_PATTERN + LAT_ZONE_PATTERN + " " + EASTING_NORTHING_PATTERN + " " + EASTING_NORTHING_PATTERN);

	public UTMRefWithHash(int lngZone, char latZone, double easting, double northing) throws NotDefinedOnUTMGridException {
		super(lngZone, latZone, easting, northing);
	}

	public static UTMRefWithHash fromString(String ref) {
		Matcher matcher = UTMREF_PATTERN.matcher(ref);

		if (!matcher.matches()) {
			throw new IllegalArgumentException("Cannot parse UTM reference " + ref +
					", needs to match pattern " + UTMREF_PATTERN.pattern());
		}

		try {
			return new UTMRefWithHash(Integer.parseInt(matcher.group(1)), matcher.group(2).charAt(0),
					Double.parseDouble(matcher.group(3)), Double.parseDouble(matcher.group(4)));
		} catch (NotDefinedOnUTMGridException e) {
			throw new IllegalArgumentException(e);
		}
	}

	/**
	 * Return the UTMRef string with rounding to the 1km-square.
	 * This is achieved by setting the last 3 digits of northing
	 * and easting to 0.
	 *
	 * This is then the reference that this squares was covered.
	 *
	 * @param latLng The latitude/longitude value to use
	 * @return A string in UTMRef notation where the last three
	 * 			digits of northing and easting are 0,
	 * 			e.g. 33U 428000.0 5366000.0
	 */
	public static String getSquareString(LatLng latLng) {
		UTMRef utmRef = latLng.toUTMRef();
		return "" +
				utmRef.getLngZone() +
				utmRef.getLatZone() + " " +
				normalize(utmRef.getEasting()) + " " +
				normalize(utmRef.getNorthing());
	}

	/**
	 * Return the LatLonRectangle for the current UTMRef.
	 *
	 * This is done by using this UTMRef as one corner and
	 * creating a second UTMRef by adding 1000 (SQUARE_SIZE) meters to
	 * both northing and easting.
	 *
	 * @return A LatLonRectangle based on northing and easting
	 * 		of this UTMRef
	 */
	public LatLonRectangle getRectangle() {
		// use separate refs for easting/northing to not cause gaps
		// caused by non-matching longitude-values
		UTMRefWithHash ref2East = new UTMRefWithHash(getLngZone(), getLatZone(),
				getEasting() + SQUARE_SIZE, getNorthing());
		UTMRefWithHash ref2North = new UTMRefWithHash(getLngZone(), getLatZone(),
				getEasting(), getNorthing() + SQUARE_SIZE);

		LatLng latLng1 = toLatLng();
		LatLng latLng2 = new LatLng(ref2North.toLatLng().getLatitude(), ref2East.toLatLng().getLongitude());

		return new LatLonRectangle(
				latLng2.getLatitude(), latLng1.getLongitude(),
				latLng1.getLatitude(), latLng2.getLongitude());
	}

	private static double normalize(double bearing) {
		// reduce accuracy to 1000 (SQUARE_SIZE) meters
		return (long)(bearing / SQUARE_SIZE) * SQUARE_SIZE;
	}

	public UTMRefWithHash up() {
		return new UTMRefWithHash(getLngZone(), getLatZone(), getEasting(), getNorthing() + SQUARE_SIZE);
	}

	public UTMRefWithHash down() {
		return new UTMRefWithHash(getLngZone(), getLatZone(), getEasting(), getNorthing() - SQUARE_SIZE);
	}

	public UTMRefWithHash right() {
		return new UTMRefWithHash(getLngZone(), getLatZone(), getEasting() + SQUARE_SIZE, getNorthing());
	}

	public UTMRefWithHash left() {
		return new UTMRefWithHash(getLngZone(), getLatZone(), getEasting() - SQUARE_SIZE, getNorthing());
	}

	@Override
	public int hashCode() {
		return Objects.hash(getLatZone(), getLngZone(), getEasting(), getNorthing());
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (!(obj instanceof UTMRef)) {
			return false;
		}
		UTMRef o = (UTMRef) obj;
		return getLatZone() == o.getLatZone() &&
				getLngZone() == o.getLngZone() &&
				getEasting() == o.getEasting() &&
				getNorthing() == o.getNorthing();
	}

	public static Set readSquares(File file) throws IOException {
		return new TreeSet<>(FileUtils.readLines(file, StandardCharsets.UTF_8)).
						stream().
						map(UTMRefWithHash::fromString).
						collect(Collectors.toSet());
	}

	@Override
	public String string() {
		return toString();
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy