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 ("\n Input 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 ("\n Input 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 ("\n Input 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