Skip to content

Commit

Permalink
Merge pull request #25 from kloverde/release/5.1.0
Browse files Browse the repository at this point in the history
Release 5.1.0 (April 20, 2024)

* Added an additional `distance` method to `DistanceCalulator`.  You can now pass a `List` of points rather than being required to use vararg/array
* `DistanceCalculator` has been updated to use [NASA's latest figure](https://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html) for Earth's radius (revised down from 6371.008 km to 6371.0 km)
* Mockito is no longer a test dependency
* Fixed Spotbugs failure regarding newline platform independence
  • Loading branch information
kloverde authored Apr 20, 2024
2 parents 81688df + 5a91ae0 commit d123a05
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 200 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Release 5.1.0 (April 20, 2024)

* Added an additional `distance` method to `DistanceCalulator`. You can now pass a `List` of points rather than being required to use vararg/array
* `DistanceCalculator` has been updated to use [NASA's latest figure](https://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html) for Earth's radius (revised down from 6371.008 km to 6371.0 km)
* Mockito is no longer a test dependency
* Fixed Spotbugs failure regarding newline platform independence

# Release 5.0.0 (April 3, 2024)

* Removed dependencies on my external `BuildScripts` and `NumberUtil` projects
Expand Down
7 changes: 3 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ buildscript {
}

plugins {
id("java")
id("com.github.spotbugs") version "6.0.10"
id("maven-publish")
id "java"
id "com.github.spotbugs" version "6.0.10"
id "maven-publish"
}

sourceCompatibility = javaSourceCompatibility
Expand All @@ -20,7 +20,6 @@ repositories {
dependencies {
testImplementation platform("org.junit:junit-bom:5.10.2")
testImplementation "org.junit.jupiter:junit-jupiter"
testImplementation "org.mockito:mockito-junit-jupiter:5.11.0"
testRuntimeOnly "org.junit.platform:junit-platform-launcher"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,6 @@ public String toString() {
}

public static String getRangeError() {
return LAT_LON_RANGE_ERROR.formatted(MAX_VALUE, MAX_VALUE, (int) MAX_VALUE, (int) MAX_VALUE);
return LAT_LON_RANGE_ERROR.replaceAll("\n", "%n").formatted(MAX_VALUE, MAX_VALUE, (int) MAX_VALUE, (int) MAX_VALUE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,6 @@ public String toString() {
}

public static String getRangeError() {
return LAT_LON_RANGE_ERROR.formatted(MAX_VALUE, MAX_VALUE, (int) MAX_VALUE, (int) MAX_VALUE);
return LAT_LON_RANGE_ERROR.replaceAll("\n", "%n").formatted(MAX_VALUE, MAX_VALUE, (int) MAX_VALUE, (int) MAX_VALUE);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public static <T extends CompassDirection> Bearing<T> backAzimuth(final Class<T>
}

private static <T extends CompassDirection> Bearing<T> newBearing(final Class<T> compassType, final BigDecimal angle) {
failIf(compassType == null, () -> COMPASS_TYPE_NULL);
failIf(compassType == null, COMPASS_TYPE_NULL);

if (compassType.equals(CompassDirection8.class)) {
return new Bearing(CompassDirection8.getByBearing(angle), angle);
Expand All @@ -117,8 +117,8 @@ private static <T extends CompassDirection> Bearing<T> newBearing(final Class<T>
}

private static BigDecimal calculateBearing(final Point from, final Point to) {
failIf(from == null, () -> STARTING_POINT_NULL);
failIf(to == null, () -> BEARING_TO_NULL);
failIf(from == null, STARTING_POINT_NULL);
failIf(to == null, BEARING_TO_NULL);

final double fromLatRadians = from.latitude().toRadians(),
fromLonRadians = from.longitude().toRadians(),
Expand All @@ -139,7 +139,7 @@ private static BigDecimal calculateBackAzimuth(final BigDecimal bearing) {
final BigDecimal zeroedBearing;
BigDecimal backAzimuth;

failIf(bearing == null, () -> BEARING_NULL);
failIf(bearing == null, BEARING_NULL);
failIf(bearing.compareTo(ZERO) < 0 || bearing.compareTo(BD_360) > 0, () -> BEARING_OUT_OF_RANGE.formatted(bearing.toPlainString()));

zeroedBearing = bearing.compareTo(BD_360) == 0 ? ZERO : bearing;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@

package org.loverde.geographiccoordinate.calculator;

import org.loverde.geographiccoordinate.Latitude;
import org.loverde.geographiccoordinate.Longitude;
import org.loverde.geographiccoordinate.Point;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

import static org.loverde.geographiccoordinate.internal.Objects.failIf;


Expand All @@ -52,8 +54,8 @@
* </p>
*
* <p>
* The Earth radius used in calculations is the volumetric mean radius, not the equatorial radius. As of the date this
* software was written, NASA's figure for the volumetric mean radius was 6371.008 km.
* The Earth radius used in calculations is the volumetric mean radius, not the equatorial radius. As of April 2024,
* NASA's figure for the volumetric mean radius was 6371.000 km.
* </p>
*
* <p><strong>
Expand Down Expand Up @@ -123,7 +125,7 @@ public enum Unit {
/**
* @see <a href="http://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html">http://nssdc.gsfc.nasa.gov/planetary/factsheet/earthfact.html</a>
*/
private static final double EARTH_RADIUS_KILOMETERS = 6371.008;
private static final double EARTH_RADIUS_KILOMETERS = 6371;


/**
Expand All @@ -139,45 +141,56 @@ public enum Unit {
* READ AND UNDERSTAND THE WAIVER PRESENT IN THIS SOFTWARE'S LICENSE.
* </strong></p>
*
* @param unit The unit of distance
* @param points A vararg of {@linkplain Point}s arranged in the order in which they are visited. You must provide
* at least 2, otherwise a {@linkplain IllegalArgumentException} will be thrown.
* @param unit The unit that the returned value will be expressed in
* @param points {@linkplain Point}s arranged in the order in which they are visited. You must provide at least 2,
* otherwise a {@linkplain IllegalArgumentException} will be thrown.
* @return The total distance traveled, expressed in terms of {@code unit}
*/
public static double distance(final Unit unit, final Point... points) {
return distance(unit, Arrays.stream(points).collect(Collectors.toList()));
}

/**
* <p>
* Gets the total distance between an unlimited number of {@linkplain Point}s. For example, if the distance from
* point A to point B is 3, and the distance from point B to point C is 2, the total distance traveled will be
* (3 + 2) = 5. Just pass {@code Point}s in the order in which they're visited.
* </p>
*
* <p><strong>
* THIS IS HOBBYIST SOFTWARE. THE AUTHOR HAS NO BACKGROUND IN, OR EVEN AN UNDERSTANDING OF, GEODESY, AND MERELY
* IMPLEMENTED FORMULAS FOUND ONLINE. DON'T ENTRUST YOUR SAFETY TO THIS SOFTWARE. NOW WOULD BE A GOOD TIME TO
* READ AND UNDERSTAND THE WAIVER PRESENT IN THIS SOFTWARE'S LICENSE.
* </strong></p>
*
* @param unit The unit that the returned value will be expressed in
* @param points {@linkplain Point}s arranged in the order in which they are visited. You must provide at least 2,
* otherwise a {@linkplain IllegalArgumentException} will be thrown.
* @return The total distance traveled, expressed in terms of {@code unit}
*/
public static double distance(final Unit unit, final List<Point> points) {
failIf(unit == null, () -> "Unit is null");
failIf(points == null, () -> "Points are null");
failIf(points.length < 2, () -> "Need to provide at least 2 points");
failIf(points.size() < 2, () -> "Need to provide at least 2 points");

double distance = 0;
Point previous = points[0];

for (int i = 1; i < points.length; i++) {
final Point current = points[i];

if (previous == null) throw new IllegalArgumentException("points " + (i - 1) + " is null");
if (current == null) throw new IllegalArgumentException("points " + i + " is null");

final Latitude latitude1 = previous.latitude();
final Latitude latitude2 = current.latitude();
Point previous = points.get(0);

final Longitude longitude1 = previous.longitude();
final Longitude longitude2 = current.longitude();
for (int i = 1; i < points.size(); i++) {
final Point current = points.get(i);

failIf(latitude1 == null, () -> "Latitude 1 is null");
failIf(latitude2 == null, () -> "Latitude 2 is null");
failIf(longitude1 == null, () -> "Longitude 1 is null");
failIf(longitude2 == null, () -> "Longitude 2 is null");
failIf(previous == null, "point %d is null".formatted(i - 1));
failIf(current == null, "point %d is null".formatted(i));

final double lat1 = latitude1.toRadians(),
lat2 = latitude2.toRadians(),
lon1 = longitude1.toRadians(),
lon2 = longitude2.toRadians(),
final double lat1 = previous.latitude().toRadians(),
lat2 = current.latitude().toRadians(),
lon1 = previous.longitude().toRadians(),
lon2 = current.longitude().toRadians(),
deltaLat = lat2 - lat1,
deltaLon = lon2 - lon1;

final double d = (2.0d * EARTH_RADIUS_KILOMETERS) * Math.asin(Math.sqrt(Math.pow(Math.sin(deltaLat / 2.0d), 2.0d)
+ (Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon / 2.0d), 2.0d))));
+ (Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(deltaLon / 2.0d), 2.0d))));

distance += d * unit.perKilometer;
previous = current;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,15 @@ public static void failIf(final boolean isFailed, final Supplier<String> iaeMess
throw new IllegalArgumentException(iaeMessage.get());
}
}

/**
* Shorthand for IF statements that throw IllegalArgumentException
* @param isFailed The result of the check
* @param iaeMessage Exception message
*/
public static void failIf(final boolean isFailed, final String iaeMessage) {
if (isFailed) {
throw new IllegalArgumentException(iaeMessage);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,15 +36,15 @@
import static org.junit.jupiter.api.Assertions.*;
import static org.loverde.geographiccoordinate.calculator.BearingCalculator.backAzimuth;
import static org.loverde.geographiccoordinate.calculator.BearingCalculator.initialBearing;
import static org.loverde.geographiccoordinate.exception.ExceptionMessages.*;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.when;
import static org.loverde.geographiccoordinate.exception.ExceptionMessages.BEARING_NULL;
import static org.loverde.geographiccoordinate.exception.ExceptionMessages.BEARING_OUT_OF_RANGE;
import static org.loverde.geographiccoordinate.exception.ExceptionMessages.COMPASS_TYPE_NULL;
import static org.loverde.geographiccoordinate.exception.ExceptionMessages.STARTING_POINT_NULL;

import java.math.BigDecimal;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.loverde.geographiccoordinate.Bearing;
import org.loverde.geographiccoordinate.Latitude;
import org.loverde.geographiccoordinate.Longitude;
Expand All @@ -53,17 +53,12 @@
import org.loverde.geographiccoordinate.compass.CompassDirection32;
import org.loverde.geographiccoordinate.compass.CompassDirection8;
import org.loverde.geographiccoordinate.exception.ExceptionMessages;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;


@ExtendWith(MockitoExtension.class)
class BearingCalculatorTest {

@Mock
private Point point1;

@Mock
private Point point2;


Expand All @@ -75,11 +70,8 @@ void setUp() {
final Latitude latitude2 = new Latitude(38, 54, 17, Latitude.Direction.NORTH);
final Longitude longitude2 = new Longitude(77, 0, 59, Longitude.Direction.WEST);

lenient().when(point1.latitude()).thenReturn(latitude1);
lenient().when(point1.longitude()).thenReturn(longitude1);

lenient().when(point2.latitude()).thenReturn(latitude2);
lenient().when(point2.longitude()).thenReturn(longitude2);
point1 = new Point(latitude1, longitude1);
point2 = new Point(latitude2, longitude2);
}

@Test
Expand All @@ -88,44 +80,12 @@ void initialBearing_nullCompassDirectionType() {
assertEquals(COMPASS_TYPE_NULL, e.getMessage());
}

@Test
void initialBearing_nullFromLatitude() {
when(point1.latitude()).thenReturn(null);

Exception e = assertThrows(IllegalArgumentException.class, () -> initialBearing(CompassDirection8.class, point1, point2));
assertEquals(BEARING_FROM_LATITUDE_NULL, e.getMessage());
}

@Test
void initialBearing_nullFromLongitude() {
when(point1.longitude()).thenReturn(null);

Exception e = assertThrows(IllegalArgumentException.class, () -> initialBearing(CompassDirection8.class, point1, point2));
assertEquals(BEARING_FROM_LONGITUDE_NULL, e.getMessage());
}

@Test
void initialBearing_nullFromPoint() {
Exception e = assertThrows(IllegalArgumentException.class, () -> initialBearing(CompassDirection8.class, null, point2));
assertEquals(STARTING_POINT_NULL, e.getMessage());
}

@Test
void initialBearing_nullToLatitude() {
when(point2.latitude()).thenReturn(null);

Exception e = assertThrows(IllegalArgumentException.class, () -> initialBearing(CompassDirection8.class, point1, point2));
assertEquals(BEARING_TO_LATITUDE_NULL, e.getMessage());
}

@Test
void initialBearing_nullToLongitude() {
when(point2.longitude()).thenReturn(null);

Exception e = assertThrows(IllegalArgumentException.class, () -> initialBearing(CompassDirection8.class, point1, point2));
assertEquals(BEARING_TO_LONGITUDE_NULL, e.getMessage());
}

@Test
void initialBearing_nullToPoint() {
Exception e = assertThrows(IllegalArgumentException.class, () -> initialBearing(CompassDirection8.class, point1, null));
Expand Down
Loading

0 comments on commit d123a05

Please sign in to comment.