Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -164,14 +165,13 @@ public static String generateBboxHtml(Object multipolygon, ObjectMapper objectMa
Polygon normalizedPolygon = (Polygon) normalizedBbox.getGeometryN(i);
Envelope envelope = normalizedPolygon.getEnvelopeInternal();

String north = String.valueOf(envelope.getMaxY());
String south = String.valueOf(envelope.getMinY());
String west = String.valueOf(envelope.getMinX());
String east = String.valueOf(envelope.getMaxX());
String north = formatCoordinate(envelope.getMaxY());
String south = formatCoordinate(envelope.getMinY());
String west = formatCoordinate(envelope.getMinX());
String east = formatCoordinate(envelope.getMaxX());

bboxCounter++;
int displayIndex = bboxCounter > 1 ? bboxCounter : 0;
html.append(buildBboxSection(north, south, west, east, displayIndex));
html.append(buildBboxSection(north, south, west, east));
}
}

Expand Down Expand Up @@ -231,6 +231,13 @@ public static String generatePolygonHtml(Object multipolygon, ObjectMapper objec
}
}

/**
* Format a coordinate to a fixed 5 decimal places (~1m precision), avoiding scientific notation.
*/
protected static String formatCoordinate(double value) {
return BigDecimal.valueOf(value).setScale(5, RoundingMode.HALF_UP).toPlainString();
}

/**
* Remove the GeoJSON closing point (where the last vertex repeats the first) to get the unique vertices.
*
Expand Down Expand Up @@ -583,8 +590,8 @@ protected static String buildPolygonSection(List<List<BigDecimal>> vertices, int
for (int i = 0; i < vertices.size(); i++) {
List<BigDecimal> point = vertices.get(i);
// GeoJSON stores [lon, lat]; display latitude-first per geographic convention.
String lon = point.get(0).toPlainString();
String lat = point.get(1).toPlainString();
String lon = formatCoordinate(point.get(0).doubleValue());
String lat = formatCoordinate(point.get(1).doubleValue());
coordinateRows.append(buildCoordinateRow("Point " + (i + 1) + ": (" + lat + ", " + lon + ")"));
}

Expand Down Expand Up @@ -632,8 +639,8 @@ protected static String buildPolygonSection(List<List<BigDecimal>> vertices, int
/**
* Build a bounding box section showing its north, west, south and east bounds
*/
protected static String buildBboxSection(String north, String south, String west, String east, int index) {
String title = index > 0 ? "Bounding Box " + index : "Bounding Box Selection";
protected static String buildBboxSection(String north, String south, String west, String east) {
String title = "Bounding Box Selection";

// Coordinate display order groups the latitude bounds (N, S) then the longitude bounds (W, E).
// Keep this list as the single source of truth for the order.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ void testPolygonImageResourceExists() throws IOException {
*/
@Test
void testSingleBbox() {
String html = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0", 0);
String html = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0");

assertTrue(html.contains("Bounding Box Selection"));
assertTrue(html.contains("N: -40.0"));
Expand All @@ -53,7 +53,7 @@ void testSingleBbox() {
*/
@Test
void testBboxCoordinateOrder() {
String html = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0", 0);
String html = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0");

int n = html.indexOf("N: -40.0");
int s = html.indexOf("S: -41.0");
Expand All @@ -64,49 +64,69 @@ void testBboxCoordinateOrder() {
}

/**
* Test multiple bboxes with numbers
* Test that every bbox always shows "Bounding Box Selection", never a number
*/
@Test
void testMultipleBboxes() {
String html1 = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0", 1);
String html2 = EmailUtils.buildBboxSection("-38.0", "-39.0", "147.0", "148.0", 2);
String html1 = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0");
String html2 = EmailUtils.buildBboxSection("-38.0", "-39.0", "147.0", "148.0");

assertTrue(html1.contains("Bounding Box 1"));
assertTrue(html2.contains("Bounding Box 2"));
assertTrue(html1.contains("Bounding Box Selection"));
assertTrue(html2.contains("Bounding Box Selection"));
assertFalse(html2.contains("Bounding Box 2"));
}

/**
* Test decimal formatting - now tests that original string values are preserved
* Test coordinates are rounded to a fixed 5 decimal places
*/
@Test
void testDecimalFormat() {
String html = EmailUtils.buildBboxSection("-35.12345", "-36.54321", "150.11111", "151.99999", 0);
void testCoordinateRoundsToFiveDecimals() {
assertEquals("-35.12346", EmailUtils.formatCoordinate(-35.123456789));
assertEquals("145.00000", EmailUtils.formatCoordinate(145.0));
}

assertTrue(html.contains("N: -35.12345"));
assertTrue(html.contains("S: -36.54321"));
assertTrue(html.contains("W: 150.11111"));
assertTrue(html.contains("E: 151.99999"));
/**
* Test coordinates never use scientific notation
*/
@Test
void testCoordinateAvoidsScientificNotation() {
assertEquals("0.00000", EmailUtils.formatCoordinate(4.9E-324));
assertEquals("-11.91981", EmailUtils.formatCoordinate(-11.919807423710694));
}

/**
* Test scientific notation values are preserved
* Test that generated bbox HTML rounds high-precision input to 5 decimals with no scientific notation
*/
@Test
void testScientificNotation() {
String html = EmailUtils.buildBboxSection("4.9E-324", "-11.919807423710694", "-45.42305428582753", "4.9E-324", 0);
void testGenerateBboxHtmlRoundsCoordinates() {
Map<String, Object> bbox = Map.of(
"type", "MultiPolygon",
"coordinates", List.of(
List.of(
List.of(
List.of(145.123456789, -40.987654321),
List.of(145.123456789, -41.0),
List.of(146.0, -41.0),
List.of(146.0, -40.987654321),
List.of(145.123456789, -40.987654321)
)
)
)
);

String html = EmailUtils.generateBboxHtml(bbox, new ObjectMapper());

assertTrue(html.contains("N: 4.9E-324"));
assertTrue(html.contains("S: -11.919807423710694"));
assertTrue(html.contains("W: -45.42305428582753"));
assertTrue(html.contains("E: 4.9E-324"));
assertTrue(html.contains("W: 145.12346"));
assertTrue(html.contains("N: -40.98765"));
assertFalse(html.contains("E-"));
}

/**
* Test image placeholder exists
*/
@Test
void testImagePlaceholder() {
String html = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0", 0);
String html = EmailUtils.buildBboxSection("-40.0", "-41.0", "145.0", "146.0");

assertTrue(html.contains("{{BBOX_IMG}}"));
}
Expand Down Expand Up @@ -327,8 +347,8 @@ void testSinglePolygon() {
String html = EmailUtils.buildPolygonSection(vertices, 0);

assertTrue(html.contains("Polygon Selection"));
assertTrue(html.contains("Point 1: (-40.0, 145.0)"));
assertTrue(html.contains("Point 5: (-41.0, 144.5)"));
assertTrue(html.contains("Point 1: (-40.00000, 145.00000)"));
assertTrue(html.contains("Point 5: (-41.00000, 144.50000)"));
}

/**
Expand All @@ -352,12 +372,12 @@ void testMultiplePolygons() {
}

/**
* Test polygon vertices preserve full precision (no scientific notation)
* Test polygon vertices are rounded to 5 decimals (no scientific notation)
*/
@Test
void testPolygonDecimalFormat() {
List<List<BigDecimal>> vertices = List.of(
List.of(new BigDecimal("150.11111"), new BigDecimal("-35.12345")),
List.of(new BigDecimal("150.123456"), new BigDecimal("-35.123454")),
List.of(new BigDecimal("151.99999"), new BigDecimal("-36.54321")),
List.of(new BigDecimal("152.50000"), new BigDecimal("-37.00001")),
List.of(new BigDecimal("151.00000"), new BigDecimal("-38.00002")),
Expand All @@ -366,7 +386,7 @@ void testPolygonDecimalFormat() {

String html = EmailUtils.buildPolygonSection(vertices, 0);

assertTrue(html.contains("Point 1: (-35.12345, 150.11111)"));
assertTrue(html.contains("Point 1: (-35.12345, 150.12346)"));
assertTrue(html.contains("Point 2: (-36.54321, 151.99999)"));
}

Expand Down
Loading