Skip to content

Commit 94977a6

Browse files
committed
add: TPoint_MakeCoords: create a sequence of coordinates based on arrays of coordinates
1 parent ff4cf11 commit 94977a6

1 file changed

Lines changed: 396 additions & 0 deletions

File tree

Lines changed: 396 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,396 @@
1+
package examples;
2+
3+
import jnr.ffi.Pointer;
4+
import jnr.ffi.Memory;
5+
import jnr.ffi.Runtime;
6+
import types.temporal.TInterpolation;
7+
8+
import java.time.OffsetDateTime;
9+
10+
import static functions.functions.*;
11+
12+
/**
13+
* Demonstrates creating temporal point sequences from coordinate arrays.
14+
*
15+
* Alternative Construction Method:
16+
* Instead of creating TPoint from individual instants, this approach uses
17+
* arrays of coordinates (x[], y[], z[], timestamps[]) to build sequences directly.
18+
*
19+
* This could be useful when data comes from:
20+
* - GPS logs (CSV with separate x, y, time columns)
21+
* - Sensor arrays (parallel data streams)
22+
* - Scientific instruments (time-series measurements)
23+
*
24+
* The program demonstrates three variants:
25+
* 1. 3D Point (x, y, z) - Projected coordinates (SRID 5676 - UTM 46N)
26+
* 2. 2D Point (x, y) - Projected coordinates (SRID 5676)
27+
* 3. 2D Point (x, y) - Geographic coordinates (SRID 4326 - WGS84)
28+
*
29+
* Function: tpointseq_make_coords(x[], y[], z[], times[], count, srid, ...)
30+
*/
31+
public class N15_TPoint_MakeCoords {
32+
33+
// PostgreSQL epoch: 2000-01-01 00:00:00 UTC
34+
private static final long POSTGRES_EPOCH_MICROSECONDS = 946684800000000L;
35+
36+
/**
37+
* Parse timestamp string to Unix timestamp (seconds since 1970-01-01)
38+
*
39+
* tpointseq_make_coords() expects Unix timestamps in seconds
40+
*/
41+
private static long parseTimestamp(String timeStr) {
42+
// Parse string to OffsetDateTime
43+
OffsetDateTime odt = pg_timestamptz_in(timeStr, -1);
44+
45+
// Convert to Java Instant
46+
java.time.Instant instant = odt.toInstant();
47+
48+
// Return Unix epoch SECONDS (not microseconds, no PostgreSQL epoch adjustment)
49+
return instant.getEpochSecond();
50+
}
51+
52+
53+
/**
54+
* SECTION 1: 3D Point Sequence (Projected Coordinates)
55+
* Creates a 3D temporal point sequence with elevation (z coordinate)
56+
*/
57+
private static void demonstrate3DProjected() {
58+
System.out.println("\n" + "=".repeat(60));
59+
System.out.println("SECTION 1: 3D Point Sequence (Projected - UTM 46N)");
60+
System.out.println("=".repeat(60));
61+
62+
// Coordinate arrays (UTM coordinates in meters)
63+
double[] xcoords = {691875.63, 691876.45, 691875.82, 691876.91};
64+
double[] ycoords = {6176943.21, 6176944.65, 6176943.54, 6176944.98};
65+
double[] zcoords = {10.5, 12.3, 11.8, 13.2}; // Elevation in meters
66+
67+
// Time array
68+
String[] timeStrs = {
69+
"2000-01-01 00:00:00",
70+
"2000-01-02 00:00:00",
71+
"2000-01-03 00:00:00",
72+
"2000-01-04 00:00:00"
73+
};
74+
75+
int count = 4;
76+
77+
System.out.println("\nInput Data:");
78+
System.out.println("┌─ COORDINATE ARRAYS ──────────────────────");
79+
for (int i = 0; i < count; i++) {
80+
System.out.printf("│ Point %d: x=%.2f, y=%.2f, z=%.2f @ %s\n",
81+
i + 1, xcoords[i], ycoords[i], zcoords[i], timeStrs[i]);
82+
}
83+
System.out.println("└──────────────────────────────────────────");
84+
Runtime runtime = Runtime.getSystemRuntime();
85+
86+
// Allocate native memory for coordinate arrays
87+
Pointer xPtr = Memory.allocate(runtime, Double.BYTES * count);
88+
Pointer yPtr = Memory.allocate(runtime, Double.BYTES * count);
89+
Pointer zPtr = Memory.allocate(runtime, Double.BYTES * count);
90+
91+
// Copy Java arrays to native memory
92+
for (int i = 0; i < count; i++) {
93+
xPtr.putDouble(i * Double.BYTES, xcoords[i]);
94+
yPtr.putDouble(i * Double.BYTES, ycoords[i]);
95+
zPtr.putDouble(i * Double.BYTES, zcoords[i]);
96+
}
97+
98+
// Allocate native memory for timestamps array
99+
Pointer timesPtr = Memory.allocate(runtime, Long.BYTES * count);
100+
101+
// Convert and store timestamps
102+
for (int i = 0; i < count; i++) {
103+
long timestamp = parseTimestamp(timeStrs[i]);
104+
timesPtr.putLong(i * Long.BYTES, timestamp);
105+
}
106+
107+
// Create 3D sequence from coordinate arrays
108+
Pointer seq = tpointseq_make_coords(
109+
xPtr, // Pointer to X coordinates
110+
yPtr, // Pointer to Y coordinates
111+
zPtr, // Pointer to Z coordinates (elevation)
112+
timesPtr, // Pointer to timestamps
113+
count, // Number of points
114+
5676, // SRID (UTM Zone 46N)
115+
false, // Not geodetic (projected)
116+
true, // Lower bound inclusive
117+
true, // Upper bound inclusive
118+
TInterpolation.LINEAR.getValue(), // Interpolation: 1 = Linear
119+
true // Normalize
120+
);
121+
122+
// Output as EWKT
123+
String ewkt = tspatial_as_ewkt(seq, 2);
124+
125+
System.out.println("\n┌─ RESULT (3D SEQUENCE) ───────────────────");
126+
System.out.println("│ EWKT:");
127+
System.out.println("│ " + ewkt);
128+
System.out.println("│");
129+
System.out.println("│ Interpretation:");
130+
System.out.println("│ - SRID 5676 = UTM Zone 46N (projected)");
131+
System.out.println("│ - 3D points with elevation (Z coordinate)");
132+
System.out.println("│ - Linear interpolation between points");
133+
System.out.println("└──────────────────────────────────────────");
134+
}
135+
136+
/**
137+
* SECTION 2: 2D Point Sequence (Projected Coordinates)
138+
* Creates a 2D temporal point sequence without elevation
139+
*/
140+
private static void demonstrate2DProjected() {
141+
System.out.println("\n" + "=".repeat(60));
142+
System.out.println("SECTION 2: 2D Point Sequence (Projected - UTM 46N)");
143+
System.out.println("=".repeat(60));
144+
145+
// Coordinate arrays (same as 3D, but no Z)
146+
double[] xcoords = {691875.63, 691876.45, 691875.82, 691876.91};
147+
double[] ycoords = {6176943.21, 6176944.65, 6176943.54, 6176944.98};
148+
149+
// Time array
150+
String[] timeStrs = {
151+
"2000-01-01 00:00:00",
152+
"2000-01-02 00:00:00",
153+
"2000-01-03 00:00:00",
154+
"2000-01-04 00:00:00"
155+
};
156+
157+
int count = 4;
158+
159+
System.out.println("\nInput Data:");
160+
System.out.println("┌─ COORDINATE ARRAYS ──────────────────────");
161+
for (int i = 0; i < count; i++) {
162+
System.out.printf("│ Point %d: x=%.2f, y=%.2f @ %s\n",
163+
i + 1, xcoords[i], ycoords[i], timeStrs[i]);
164+
}
165+
System.out.println("└──────────────────────────────────────────");
166+
Runtime runtime = Runtime.getSystemRuntime();
167+
168+
// Allocate native memory for coordinate arrays
169+
Pointer xPtr = Memory.allocate(runtime, Double.BYTES * count);
170+
Pointer yPtr = Memory.allocate(runtime, Double.BYTES * count);
171+
172+
// Copy Java arrays to native memory
173+
for (int i = 0; i < count; i++) {
174+
xPtr.putDouble(i * Double.BYTES, xcoords[i]);
175+
yPtr.putDouble(i * Double.BYTES, ycoords[i]);
176+
}
177+
178+
// Allocate native memory for timestamps array
179+
Pointer timesPtr = Memory.allocate(runtime, Long.BYTES * count);
180+
181+
// Convert and store timestamps
182+
for (int i = 0; i < count; i++) {
183+
long timestamp = parseTimestamp(timeStrs[i]);
184+
timesPtr.putLong(i * Long.BYTES, timestamp);
185+
}
186+
187+
// Create 2D sequence from coordinate arrays
188+
// Pass null for zPtr to create 2D points
189+
Pointer seq = tpointseq_make_coords(
190+
xPtr, // Pointer to X coordinates
191+
yPtr, // Pointer to Y coordinates
192+
null, // No Z coordinates (2D)
193+
timesPtr, // Pointer to timestamps
194+
count, // Number of points
195+
5676, // SRID (UTM Zone 46N)
196+
false, // Not geodetic (projected)
197+
true, // Lower bound inclusive
198+
true, // Upper bound inclusive
199+
TInterpolation.LINEAR.getValue(), // Interpolation: 1 = Linear
200+
true // Normalize
201+
);
202+
203+
// Output as EWKT
204+
String ewkt = tspatial_as_ewkt(seq, 2);
205+
206+
System.out.println("\n┌─ RESULT (2D SEQUENCE) ───────────────────");
207+
System.out.println("│ EWKT:");
208+
System.out.println("│ " + ewkt);
209+
System.out.println("│");
210+
System.out.println("│ Interpretation:");
211+
System.out.println("│ - SRID 5676 = UTM Zone 46N (projected)");
212+
System.out.println("│ - 2D points (no elevation)");
213+
System.out.println("│ - Same coordinates as 3D, but Z omitted");
214+
System.out.println("└──────────────────────────────────────────");
215+
}
216+
217+
/**
218+
* SECTION 3: 2D Point Sequence (Geographic Coordinates)
219+
* Creates a geographic temporal point sequence (latitude/longitude)
220+
*/
221+
private static void demonstrate2DGeographic() {
222+
System.out.println("\n" + "=".repeat(60));
223+
System.out.println("SECTION 3: 2D Point Sequence (Geographic - WGS84)");
224+
System.out.println("=".repeat(60));
225+
226+
// Geographic coordinates (longitude, latitude)
227+
double[] xcoords = {2.349014, 2.349156, 2.349089, 2.349201}; // Longitude
228+
double[] ycoords = {48.852968, 48.853142, 48.853034, 48.853215}; // Latitude
229+
230+
// Time array
231+
String[] timeStrs = {
232+
"2000-01-01 00:00:00",
233+
"2000-01-02 00:00:00",
234+
"2000-01-03 00:00:00",
235+
"2000-01-04 00:00:00"
236+
};
237+
238+
int count = 4;
239+
240+
System.out.println("\nInput Data (Paris, France):");
241+
System.out.println("┌─ COORDINATE ARRAYS ──────────────────────");
242+
for (int i = 0; i < count; i++) {
243+
System.out.printf("│ Point %d: lon=%.6f, lat=%.6f @ %s\n",
244+
i + 1, xcoords[i], ycoords[i], timeStrs[i]);
245+
}
246+
System.out.println("└──────────────────────────────────────────");
247+
Runtime runtime = Runtime.getSystemRuntime();
248+
249+
// Allocate native memory for coordinate arrays
250+
Pointer xPtr = Memory.allocate(runtime, Double.BYTES * count);
251+
Pointer yPtr = Memory.allocate(runtime, Double.BYTES * count);
252+
253+
// Copy Java arrays to native memory
254+
for (int i = 0; i < count; i++) {
255+
xPtr.putDouble(i * Double.BYTES, xcoords[i]);
256+
yPtr.putDouble(i * Double.BYTES, ycoords[i]);
257+
}
258+
259+
// Allocate native memory for timestamps array
260+
Pointer timesPtr = Memory.allocate(runtime, Long.BYTES * count);
261+
262+
// Convert and store timestamps
263+
for (int i = 0; i < count; i++) {
264+
long timestamp = parseTimestamp(timeStrs[i]);
265+
timesPtr.putLong(i * Long.BYTES, timestamp);
266+
}
267+
268+
// Create geographic sequence from coordinate arrays
269+
Pointer seq = tpointseq_make_coords(
270+
xPtr, // Longitude
271+
yPtr, // Latitude
272+
null, // No Z coordinates
273+
timesPtr, // Pointer to timestamps
274+
count, // Number of points
275+
4326, // SRID (WGS84 - standard GPS coordinates)
276+
true, // Geodetic (geographic)
277+
true, // Lower bound inclusive
278+
true, // Upper bound inclusive
279+
TInterpolation.LINEAR.getValue(), // Interpolation: 1 = Linear
280+
true // Normalize
281+
);
282+
283+
// Output as EWKT
284+
String ewkt = tspatial_as_ewkt(seq, 6); // 6 decimals for geographic
285+
286+
System.out.println("\n┌─ RESULT (GEOGRAPHIC SEQUENCE) ───────────");
287+
System.out.println("│ EWKT:");
288+
System.out.println("│ " + ewkt);
289+
System.out.println("│");
290+
System.out.println("│ Interpretation:");
291+
System.out.println("│ - SRID 4326 = WGS84 (standard GPS)");
292+
System.out.println("│ - Geographic coordinates (lon/lat)");
293+
System.out.println("│ - Geodetic = true (distances on sphere)");
294+
System.out.println("│ - Location: Near Eiffel Tower, Paris");
295+
System.out.println("└──────────────────────────────────────────");
296+
}
297+
298+
/**
299+
* Explain the coordinate arrays approach
300+
*/
301+
private static void explainCoordinateArrays() {
302+
System.out.println("\n╔═══════════════════════════════════════════════════════════╗");
303+
System.out.println("║ COORDINATE ARRAYS CONSTRUCTION EXPLAINED ║");
304+
System.out.println("╚═══════════════════════════════════════════════════════════╝");
305+
System.out.println();
306+
System.out.println("Two Ways to Create Temporal Point Sequences:");
307+
System.out.println("───────────────────────────────────────────");
308+
System.out.println();
309+
System.out.println("┌─ METHOD 1: From Instants (Traditional) ──────────────────");
310+
System.out.println("│");
311+
System.out.println("│ TInstant inst1 = new TInstant(\"POINT(1 2)@2000-01-01\");");
312+
System.out.println("│ TInstant inst2 = new TInstant(\"POINT(2 3)@2000-01-02\");");
313+
System.out.println("│ TInstant inst3 = new TInstant(\"POINT(3 4)@2000-01-03\");");
314+
System.out.println("│");
315+
System.out.println("│ TSequence seq = new TSequence(instants, 3, ...);");
316+
System.out.println("│");
317+
System.out.println("│ Use when: Data comes as complete WKT strings");
318+
System.out.println("│");
319+
System.out.println("└──────────────────────────────────────────────────────────");
320+
System.out.println();
321+
System.out.println("┌─ METHOD 2: From Coordinate Arrays (This Program) ────────");
322+
System.out.println("│");
323+
System.out.println("│ // Java arrays");
324+
System.out.println("│ double[] x = {1, 2, 3};");
325+
System.out.println("│ double[] y = {2, 3, 4};");
326+
System.out.println("│");
327+
System.out.println("│ // Allocate native memory and copy");
328+
System.out.println("│ Pointer xPtr = Memory.allocate(runtime, Double.BYTES * 3);");
329+
System.out.println("│ for (int i = 0; i < 3; i++)");
330+
System.out.println("│ xPtr.putDouble(i * Double.BYTES, x[i]);");
331+
System.out.println("│");
332+
System.out.println("│ // Same for y and timestamps...");
333+
System.out.println("│");
334+
System.out.println("│ Pointer seq = tpointseq_make_coords(xPtr, yPtr, null,");
335+
System.out.println("│ timesPtr, 3, ...);");
336+
System.out.println("│");
337+
System.out.println("│ Use when: Data comes as separate coordinate columns");
338+
System.out.println("│");
339+
System.out.println("└──────────────────────────────────────────────────────────");
340+
System.out.println();
341+
System.out.println("When to Use Coordinate Arrays:");
342+
System.out.println("──────────────────────────────");
343+
System.out.println("✓ Sensor data: Separate streams for each dimension");
344+
System.out.println("✓ Database exports: Tabular format");
345+
System.out.println();
346+
System.out.println("Example CSV Data:");
347+
System.out.println("────────────────");
348+
System.out.println("timestamp,longitude,latitude,elevation");
349+
System.out.println("2000-01-01 00:00:00,2.349,48.853,10.5");
350+
System.out.println("2000-01-02 00:00:00,2.350,48.854,12.3");
351+
System.out.println("2000-01-03 00:00:00,2.351,48.855,11.8");
352+
System.out.println();
353+
System.out.println("→ Perfect for tpointseq_make_coords()!");
354+
System.out.println();
355+
System.out.println();
356+
}
357+
358+
public static void main(String[] args) {
359+
// Initialize MEOS
360+
meos_initialize();
361+
meos_initialize_timezone("UTC");
362+
363+
try {
364+
System.out.println("\n" + "=".repeat(60));
365+
System.out.println("Temporal Point Construction from Coordinate Arrays");
366+
System.out.println("=".repeat(60));
367+
368+
// Explain the approach
369+
explainCoordinateArrays();
370+
371+
// Run all demonstrations
372+
demonstrate3DProjected();
373+
demonstrate2DProjected();
374+
demonstrate2DGeographic();
375+
376+
System.out.println("\n" + "=".repeat(60));
377+
System.out.println("DEMONSTRATION COMPLETED!");
378+
System.out.println("=".repeat(60));
379+
System.out.println();
380+
System.out.println("Key Takeaways:");
381+
System.out.println("──────────────");
382+
System.out.println("1. Use coordinate arrays when data is in tabular format");
383+
System.out.println("2. 3D points include elevation (z coordinate)");
384+
System.out.println("3. Geographic (4326) vs Projected (5676) coordinates");
385+
System.out.println("4. More efficient than creating individual instants");
386+
System.out.println();
387+
388+
} catch (Exception e) {
389+
System.err.println("Error: " + e.getMessage());
390+
e.printStackTrace();
391+
} finally {
392+
// Finalize MEOS
393+
meos_finalize();
394+
}
395+
}
396+
}

0 commit comments

Comments
 (0)