corelle.engine 3.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,233 @@
1
+ -- drop outdated function signatures
2
+ DROP FUNCTION IF EXISTS corelle.rotate_geometry(geometry, numeric[]);
3
+ DROP FUNCTION IF EXISTS corelle.rotate_geometry(geometry, integer, integer, integer);
4
+ DROP FUNCTION IF EXISTS corelle.build_proj_string(numeric[]);
5
+ DROP FUNCTION IF EXISTS corelle.quaternion_multiply(numeric[], numeric[]);
6
+ DROP FUNCTION IF EXISTS corelle.invert_rotation(numeric[]);
7
+ DROP FUNCTION IF EXISTS corelle.rotate_geometry(geometry, double precision[]);
8
+ DROP FUNCTION IF EXISTS corelle.rotate_geometry(geometry,integer,integer,numeric,boolean);
9
+ DROP FUNCTION IF EXISTS corelle.rotate_vector(numeric[], numeric[]);
10
+
11
+ /*
12
+ Functions to rotate geometries directly in PostGIS. This allows Corelle plate rotations
13
+ to be applied to any geometry in the database. This requires plate geometries to be pre-cached
14
+ in the database for each time step and plate ID.
15
+ */
16
+ CREATE OR REPLACE FUNCTION corelle.rotate_geometry(
17
+ geom geometry,
18
+ quaternion double precision[],
19
+ wrap_lon numeric DEFAULT 0
20
+ )
21
+ RETURNS geometry
22
+ AS $$
23
+ DECLARE
24
+ projection text := corelle.build_proj_string(quaternion);
25
+ g1 geometry;
26
+ BEGIN
27
+ return ST_SetSRID(ST_Transform(geom, projection), 4326);
28
+ END;
29
+ $$ LANGUAGE plpgsql IMMUTABLE;
30
+
31
+ CREATE OR REPLACE FUNCTION corelle.invert_rotation(quaternion double precision[])
32
+ RETURNS double precision[]
33
+ AS $$
34
+ -- norm := sqrt(
35
+ -- pow(quaternion[1],2) + pow(quaternion[2],2) +
36
+ -- pow(quaternion[3],2) + pow(quaternion[4], 2)
37
+ -- );
38
+
39
+ SELECT ARRAY[
40
+ quaternion[1],
41
+ -quaternion[2],
42
+ -quaternion[3],
43
+ -quaternion[4]
44
+ ] ;
45
+ $$ LANGUAGE sql IMMUTABLE STRICT;
46
+
47
+
48
+ CREATE OR REPLACE FUNCTION corelle.rotate_vector(vector double precision[], quaternion double precision[]) RETURNS double precision[] AS $$
49
+ DECLARE
50
+ q_conj double precision[];
51
+ q_res double precision[];
52
+ r double precision[];
53
+ BEGIN
54
+ q_conj := ARRAY[
55
+ quaternion[1],
56
+ -quaternion[2],
57
+ -quaternion[3],
58
+ -quaternion[4]
59
+ ];
60
+
61
+ r := ARRAY[0, vector[1], vector[2], vector[3]];
62
+
63
+ q_res := corelle.quaternion_multiply(
64
+ corelle.quaternion_multiply(quaternion, r),
65
+ q_conj
66
+ );
67
+
68
+ RETURN ARRAY[q_res[2], q_res[3], q_res[4]];
69
+ END;
70
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
71
+
72
+ CREATE OR REPLACE FUNCTION corelle.rotate_vector(vector numeric[], quaternion numeric[]) RETURNS numeric[] AS $$
73
+ SELECT corelle.rotate_vector(
74
+ ARRAY[
75
+ vector[1]::double precision,
76
+ vector[2]::double precision,
77
+ vector[3]::double precision
78
+ ],
79
+ ARRAY[
80
+ quaternion[1]::double precision,
81
+ quaternion[2]::double precision,
82
+ quaternion[3]::double precision,
83
+ quaternion[4]::double precision
84
+ ]
85
+ )::numeric[];
86
+ $$ LANGUAGE sql IMMUTABLE STRICT;
87
+
88
+
89
+ /* Rotate a geometry and clip to a bounding plate polygon */
90
+ CREATE OR REPLACE FUNCTION corelle.rotate_geometry(
91
+ geom geometry,
92
+ _model_id integer,
93
+ _plate_id integer,
94
+ time_ma numeric,
95
+ should_clip boolean DEFAULT true
96
+ )
97
+ RETURNS geometry
98
+ AS $$
99
+ DECLARE
100
+ plate geometry;
101
+ rotation double precision[];
102
+ clipped geometry;
103
+ BEGIN
104
+
105
+ -- get rotation at closest time step
106
+ SELECT r.rotation
107
+ FROM corelle.rotation_cache r
108
+ WHERE model_id = _model_id
109
+ AND plate_id = _plate_id
110
+ AND t_step = time_ma::integer
111
+ INTO rotation;
112
+
113
+ IF time_ma != 0 AND rotation IS null THEN
114
+ RETURN null;
115
+ END IF;
116
+
117
+ /* If we're not clipping, the operation is relatively simple, and also
118
+ should be much faster. */
119
+ IF NOT should_clip THEN
120
+ IF time_ma = 0 THEN
121
+ RETURN geom;
122
+ END IF;
123
+ RETURN corelle.rotate_geometry(geom, rotation);
124
+ END IF;
125
+
126
+ /* If we're clipping, we need more information */
127
+ SELECT geom
128
+ FROM corelle.plate_polygon
129
+ WHERE model_id = _model_id
130
+ AND plate_id = _plate_id
131
+ AND coalesce(old_lim, 4000) >= time_ma
132
+ AND coalesce(young_lim, 0) < time_ma
133
+ INTO plate;
134
+
135
+ IF plate IS NULL THEN
136
+ RETURN NULL;
137
+ END IF;
138
+
139
+ IF NOT geom && plate THEN
140
+ RETURN NULL;
141
+ END IF;
142
+
143
+ clipped := ST_Intersection(
144
+ geom,
145
+ plate
146
+ );
147
+
148
+ IF time_ma = 0 THEN
149
+ RETURN clipped;
150
+ END IF;
151
+
152
+ RETURN corelle.rotate_geometry(clipped, rotation);
153
+ END;
154
+ $$ LANGUAGE plpgsql IMMUTABLE;
155
+
156
+ DROP FUNCTION IF EXISTS corelle.build_proj_string(double precision[]);
157
+ DROP FUNCTION IF EXISTS corelle.build_proj_string(double precision[], text);
158
+ DROP FUNCTION IF EXISTS corelle.build_proj_string(double precision[], text, text);
159
+ DROP FUNCTION IF EXISTS corelle.build_proj_string(double precision[], text, numeric);
160
+
161
+ /**
162
+ Builds a projection string from a quaternion. This is the core of Corelle's on-database
163
+ rotation functionality.
164
+
165
+ Big thanks to Duncan Agnew and the PROJ listserv for helping me figure out the right angular
166
+ representation to use here.
167
+ */
168
+ CREATE OR REPLACE FUNCTION corelle.build_proj_string(
169
+ quaternion double precision[],
170
+ extra_params text DEFAULT '+o_proj=longlat',
171
+ /* NOTE: lon_adjustment, in radians, is applied to the pole longitude
172
+ in order to rotate the projection to solve antimeridian issues. This is
173
+ a hack, and should be replaced with a better solution, probably involving
174
+ a fix to PROJ's ob_tran projection (to add handling of the +over parameter). */
175
+ lon_adjustment double precision DEFAULT 0
176
+ )
177
+ RETURNS text AS $$
178
+ DECLARE
179
+ new_pole double precision[];
180
+ lat_p double precision;
181
+ lon_p double precision;
182
+ lon_0 double precision;
183
+ norm double precision;
184
+ twist_q_w double precision;
185
+ twist_angle double precision;
186
+ BEGIN
187
+
188
+ new_pole := corelle.quaternion_multiply(
189
+ ARRAY[-quaternion[4], quaternion[3], -quaternion[2], quaternion[1]],
190
+ corelle.invert_rotation(quaternion)
191
+ );
192
+
193
+ lon_p := atan2(new_pole[3], new_pole[2]);
194
+ lat_p := asin(new_pole[4]);
195
+
196
+ norm := sqrt(pow(quaternion[1],2) + pow(quaternion[4], 2));
197
+
198
+ IF norm = 0 THEN
199
+ twist_q_w := 1;
200
+ ELSIF quaternion[4] < 0 THEN
201
+ twist_q_w := -quaternion[1] / norm;
202
+ ELSE
203
+ twist_q_w := quaternion[1] / norm;
204
+ END IF;
205
+
206
+ twist_angle := 2 * acos(twist_q_w);
207
+
208
+ lon_0 := lon_p - twist_angle;
209
+
210
+ RETURN format('+proj=ob_tran +o_lon_p=%sr +o_lat_p=%sr +lon_0=%sr ' || extra_params,
211
+ lon_p + lon_adjustment,
212
+ lat_p,
213
+ lon_0
214
+ );
215
+ END;
216
+ $$ LANGUAGE plpgsql IMMUTABLE;
217
+
218
+
219
+ /**
220
+ Hamilton product of two quaternions.
221
+ */
222
+ CREATE OR REPLACE FUNCTION corelle.quaternion_multiply(q double precision[], r double precision[])
223
+ RETURNS double precision[]
224
+ AS $$
225
+ BEGIN
226
+ RETURN ARRAY[
227
+ r[1]*q[1]-r[2]*q[2]-r[3]*q[3]-r[4]*q[4],
228
+ r[1]*q[2]+r[2]*q[1]-r[3]*q[4]+r[4]*q[3],
229
+ r[1]*q[3]+r[2]*q[4]+r[3]*q[1]-r[4]*q[2],
230
+ r[1]*q[4]-r[2]*q[3]+r[3]*q[2]+r[4]*q[1]
231
+ ];
232
+ END;
233
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
@@ -0,0 +1,186 @@
1
+ /** Drop old function signatures */
2
+ DROP FUNCTION IF EXISTS corelle.rotate_geometry_pointwise(geometry, numeric[]);
3
+ DROP FUNCTION IF EXISTS corelle.rotate_point(geometry, numeric[]);
4
+ DROP FUNCTION IF EXISTS corelle.sph2cart(geometry);
5
+ DROP FUNCTION IF EXISTS corelle.cart2sph(numeric, numeric, numeric);
6
+ DROP FUNCTION IF EXISTS corelle.quaternion_to_euler(numeric[]);
7
+ DROP FUNCTION IF EXISTS corelle.euler_to_quaternion(geometry, numeric);
8
+ DROP FUNCTION IF EXISTS corelle.radians(numeric);
9
+ DROP FUNCTION IF EXISTS corelle.degrees(numeric);
10
+
11
+ /**
12
+ Naïve implementation of the quaternion rotation algorithm using PostGIS functions directly.
13
+
14
+ This is quite slow compared to using PROJ directly. It is included here for reference and
15
+ testing purposes.
16
+ */
17
+ CREATE OR REPLACE FUNCTION corelle.rotate_geometry_pointwise(geom geometry, quaternion double precision[])
18
+ RETURNS geometry
19
+ AS $$
20
+ DECLARE
21
+ result geometry;
22
+ rings geometry[];
23
+ BEGIN
24
+ IF ST_GeometryType(geom) = 'ST_Point' THEN
25
+ RETURN corelle.rotate_point(geom, quaternion);
26
+ ELSIF ST_GeometryType(geom) = 'ST_MultiPoint' THEN
27
+ RETURN ST_Collect(ARRAY(
28
+ SELECT corelle.rotate_geometry_pointwise(g.geom, quaternion)
29
+ FROM ST_DumpPoints(geom) AS g
30
+ ));
31
+ ELSIF ST_GeometryType(geom) = 'ST_LineString' THEN
32
+ RETURN ST_MakeLine(ARRAY(
33
+ SELECT corelle.rotate_geometry_pointwise(g.geom, quaternion)
34
+ FROM ST_DumpPoints(geom) AS g
35
+ ));
36
+ ELSIF ST_GeometryType(geom) = 'ST_MultiLineString' THEN
37
+ RETURN ST_Collect(ARRAY(
38
+ SELECT corelle.rotate_geometry_pointwise(g.geom, quaternion)
39
+ FROM ST_Dump(geom) AS g
40
+ ));
41
+ ELSIF ST_GeometryType(geom) = 'ST_Polygon' THEN
42
+ -- don't handle rings yet...
43
+ -- Rotate interior rings
44
+ rings := ARRAY(
45
+ SELECT corelle.rotate_geometry_pointwise(ST_InteriorRingN(geom, r), quaternion)
46
+ FROM generate_series(1, ST_NumInteriorRing(geom)) AS r
47
+ );
48
+
49
+ RETURN ST_MakePolygon(corelle.rotate_geometry_pointwise(ST_ExteriorRing(geom), quaternion), rings);
50
+ ELSIF ST_GeometryType(geom) = 'ST_MultiPolygon' THEN
51
+ RETURN ST_Collect(ARRAY(
52
+ SELECT corelle.rotate_geometry_pointwise(g.geom, quaternion)
53
+ FROM ST_Dump(geom) AS g
54
+ ));
55
+ ELSE
56
+ RAISE EXCEPTION 'Unsupported geometry type: %', ST_GeometryType(geom);
57
+ END IF;
58
+ END;
59
+ $$ LANGUAGE plpgsql IMMUTABLE;
60
+
61
+ CREATE OR REPLACE FUNCTION corelle.rotate_point(point geometry, quaternion double precision[])
62
+ RETURNS geometry AS $$
63
+ DECLARE
64
+ pt double precision[] := corelle.sph2cart(point);
65
+ q_conj double precision[];
66
+ q_res double precision[];
67
+ r double precision[];
68
+ BEGIN
69
+ q_conj := ARRAY[
70
+ quaternion[1],
71
+ -quaternion[2],
72
+ -quaternion[3],
73
+ -quaternion[4]
74
+ ];
75
+
76
+ r := ARRAY[0, pt[1], pt[2], pt[3]];
77
+
78
+ q_res := corelle.quaternion_multiply(
79
+ corelle.quaternion_multiply(quaternion, r),
80
+ q_conj
81
+ );
82
+
83
+ RETURN corelle.cart2sph(
84
+ q_res[2],
85
+ q_res[3],
86
+ q_res[4]
87
+ );
88
+ END;
89
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
90
+
91
+ /**
92
+ * UTILITIES for converting between spherical and cartesian coordinates.
93
+ * These are primarily used for testing purposes.
94
+ */
95
+ CREATE OR REPLACE FUNCTION corelle.sph2cart(point geometry)
96
+ RETURNS double precision[] AS $$
97
+ DECLARE
98
+ lon double precision := corelle.radians(ST_X(point));
99
+ lat double precision := corelle.radians(ST_Y(point));
100
+ r double precision := coalesce(ST_Z(point), 1);
101
+ BEGIN
102
+ RETURN ARRAY[
103
+ r * cos(lat) * cos(lon),
104
+ r * cos(lat) * sin(lon),
105
+ r * sin(lat)
106
+ ];
107
+ END;
108
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
109
+
110
+
111
+ CREATE OR REPLACE FUNCTION corelle.cart2sph(x double precision, y double precision, z double precision)
112
+ RETURNS geometry
113
+ AS $$
114
+ DECLARE
115
+ r double precision := sqrt(x * x + y * y + z * z);
116
+ lat double precision := corelle.degrees(asin(z / r));
117
+ lon double precision := corelle.degrees(atan2(y, x));
118
+ BEGIN
119
+ IF abs(r-1) < 0.0000001 THEN
120
+ RETURN ST_SetSRID(ST_MakePoint(lon, lat), 4326);
121
+ ELSE
122
+ RETURN ST_SetSRID(ST_MakePoint(lon, lat, r), 4326);
123
+ END IF;
124
+ END;
125
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
126
+
127
+ CREATE OR REPLACE FUNCTION corelle.quaternion_to_euler(q double precision[])
128
+ RETURNS double precision[] AS $$
129
+ DECLARE
130
+ w double precision := q[1];
131
+ x double precision := q[2];
132
+ y double precision := q[3];
133
+ z double precision := q[4];
134
+ angle double precision := 2 * acos(w);
135
+ scalar double precision := sin(angle / 2);
136
+ lat double precision;
137
+ lon double precision;
138
+ BEGIN
139
+ IF scalar = 0 THEN
140
+ RETURN null;
141
+ ELSE
142
+ lat := asin(z/scalar);
143
+ lon := atan2(y/scalar, x/scalar);
144
+ RETURN ARRAY[lon, lat, angle];
145
+ END IF;
146
+ END;
147
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
148
+
149
+ CREATE OR REPLACE FUNCTION corelle.euler_to_quaternion(pole geometry, angle double precision)
150
+ RETURNS double precision[] AS $$
151
+ DECLARE
152
+ half_angle double precision := corelle.radians(angle) / 2;
153
+ scalar double precision := sin(half_angle);
154
+ v double precision[] := corelle.sph2cart(pole);
155
+ BEGIN
156
+ RETURN ARRAY[
157
+ cos(half_angle),
158
+ v[1] * scalar,
159
+ v[2] * scalar,
160
+ v[3] * scalar
161
+ ];
162
+ END;
163
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
164
+
165
+ /* Convert to radians */
166
+ CREATE OR REPLACE FUNCTION corelle.radians(degrees double precision)
167
+ RETURNS double precision AS $$
168
+ BEGIN
169
+ RETURN degrees * pi() / 180;
170
+ END;
171
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
172
+
173
+ /* Convert to degrees */
174
+ CREATE OR REPLACE FUNCTION corelle.degrees(radians double precision)
175
+ RETURNS double precision AS $$
176
+ DECLARE
177
+ uncorrected double precision := radians * 180 / pi();
178
+ BEGIN
179
+ -- Return data in the right quadrant
180
+ IF uncorrected < -180 THEN
181
+ RETURN uncorrected + 360;
182
+ ELSE
183
+ RETURN uncorrected;
184
+ END IF;
185
+ END;
186
+ $$ LANGUAGE plpgsql IMMUTABLE STRICT;
@@ -0,0 +1,47 @@
1
+ DROP MATERIALIZED VIEW IF EXISTS corelle.plate_polygon_cache;
2
+ CREATE MATERIALIZED VIEW corelle.plate_polygon_cache AS
3
+ WITH a AS (
4
+ -- Basic query for plate polygons
5
+ SELECT
6
+ pp.id,
7
+ pp.plate_id,
8
+ coalesce(young_lim, 0) young_lim,
9
+ old_lim,
10
+ p.name,
11
+ ST_AsGeoJSON(geometry)::jsonb geometry,
12
+ pp.model_id
13
+ FROM corelle.plate_polygon pp
14
+ JOIN corelle.plate p
15
+ ON pp.plate_id = p.id
16
+ AND pp.model_id = p.model_id
17
+ ),
18
+ b AS (
19
+ SELECT json_build_object(
20
+ 'id', plate_id,
21
+ 'properties', json_build_object(
22
+ 'id', a.id,
23
+ 'plate_id', plate_id,
24
+ 'young_lim', young_lim,
25
+ 'old_lim', old_lim,
26
+ 'name', name
27
+ ),
28
+ 'type', 'Feature',
29
+ 'geometry', geometry
30
+ ) r,
31
+ model_id
32
+ FROM a
33
+ ),
34
+ c AS (
35
+ SELECT
36
+ model_id,
37
+ json_agg(r) geojson
38
+ FROM b
39
+ GROUP BY model_id
40
+ )
41
+ SELECT
42
+ m.id model_id,
43
+ m.name model_name,
44
+ c.geojson
45
+ FROM c
46
+ JOIN corelle.model m
47
+ ON m.id = c.model_id;
@@ -0,0 +1,11 @@
1
+ from sqlalchemy import MetaData, Table, text
2
+
3
+ _model_id = text("SELECT id FROM corelle.model WHERE name = :name")
4
+
5
+
6
+ def model_id(conn, name):
7
+ return conn.execute(_model_id, dict(name=name)).scalar()
8
+
9
+
10
+ def reflect_table(conn, name):
11
+ return Table(name, MetaData(), schema="corelle", autoload_with=conn)
@@ -0,0 +1,31 @@
1
+ Metadata-Version: 2.4
2
+ Name: corelle.engine
3
+ Version: 3.0.0
4
+ Summary: Plate-rotation models and rotation engine for the Corelle system
5
+ Author: Daven Quinn
6
+ Author-email: Daven Quinn <dev@davenquinn.com>
7
+ License-Expression: MIT
8
+ Classifier: Programming Language :: Python :: 3
9
+ Classifier: Programming Language :: Python :: 3.10
10
+ Classifier: Programming Language :: Python :: 3.11
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Python :: 3.13
13
+ Classifier: Programming Language :: Python :: 3.14
14
+ Requires-Dist: click>=8.1,<9
15
+ Requires-Dist: corelle-client>=2.2,<3
16
+ Requires-Dist: macrostrat-database>=4.7,<5
17
+ Requires-Dist: macrostrat-utils>=1.0.1,<2
18
+ Requires-Dist: numba>=0.63.1,<0.69
19
+ Requires-Dist: numpy>=2.0.0,<3
20
+ Requires-Dist: numpy-quaternion>=2024.0.13,<2025.0.0
21
+ Requires-Dist: rich>12.6.0,<16
22
+ Requires-Dist: typer>0.12.0,<0.30
23
+ Requires-Dist: geoalchemy2>0.14.0,<0.22
24
+ Requires-Dist: sqlalchemy>=2.0.25,<2.1
25
+ Requires-Dist: fiona>=1.10.1,<2 ; extra == 'import'
26
+ Requires-Dist: pyyaml>=6.0,<7 ; extra == 'import'
27
+ Requires-Dist: wget>=3.2,<4 ; extra == 'import'
28
+ Requires-Dist: ipython>=8.0,<10 ; extra == 'shell'
29
+ Requires-Python: >=3.10, <4
30
+ Provides-Extra: import
31
+ Provides-Extra: shell
@@ -0,0 +1,31 @@
1
+ corelle/engine/__init__.py,sha256=QPWtj5wDRTINDxVUL7XPqG3HoxHNvYOg08EnuSZB2Hc,21
2
+ corelle/engine/cache.py,sha256=MWf27Buo5mmYhYuV076rLl_lQV_L4TXZRnLkkg-NPWc,2175
3
+ corelle/engine/cli.py,sha256=NeyqFeIe3TMDwKDyIW6YDB1jBqZDA_ReUQr2Jz7-URY,4610
4
+ corelle/engine/database.py,sha256=OfVsBmcBufKJX1v0EsgyRin0xo3TbD5Hyxp4L_1Yl3U,951
5
+ corelle/engine/load_data.py,sha256=KBlb8xYzR-QbU8UXYO48g7hP89xmoMFj3-4ZJp73HRM,10557
6
+ corelle/engine/query/__init__.py,sha256=iM0JjZh-whRKlE8Hg2zIXC2Mo8IVVcauXCs9CDnGDwQ,171
7
+ corelle/engine/query/active-plates-at-time.sql,sha256=H6QEQXOmIWrAdx49T6YEGnx53OEqyOFUB1beI3J-WZk,284
8
+ corelle/engine/query/cache-feature-dataset.sql,sha256=uTEv2SHwZOD4oHAUuaIph0avUwGmXtwRyj-rrNPphvs,910
9
+ corelle/engine/query/delete-extraneous-cache.sql,sha256=UHHOcKrKaaNpbxP8K3FWkTzORBeJ3TSy-78DyOiQ7Ak,210
10
+ corelle/engine/query/feature-dataset-cached.sql,sha256=_NoCafzkym-jRnT3h6F5drMvN8blHXT1vIW_Cn3JVCQ,101
11
+ corelle/engine/query/feature-dataset.sql,sha256=R8sh7C4avZLxBeD_knZVJmpzksv3hDUXXdAFYbdfKjk,588
12
+ corelle/engine/query/modern-plate-polygons-cached.sql,sha256=oA5__Ag7QAgRbQ-sfwrY_bqVPqj_zW0-W_bjFMTbnqA,79
13
+ corelle/engine/query/modern-plate-polygons.sql,sha256=mRxu7BwAm2_PhHtgJr3V0dHvDVo3EdqzgF-nahLELJI,298
14
+ corelle/engine/query/plate-for-point.sql,sha256=h0ULqoW0TV9OkOcadBwn4KAi0m1H26KPE6U5OVPsPj4,254
15
+ corelle/engine/query/plate-time-ranges.sql,sha256=ycASErhdOZnUhLfE-AgrRNAbhAU8kLnmUsve-HMnvMw,225
16
+ corelle/engine/query/plates-for-model.sql,sha256=ocOTgNVpf42CiD0EIZOueDuEZgxhffP7AqaEMUp_2JA,109
17
+ corelle/engine/query/rotation-pairs-for-model.sql,sha256=j5-hcSuQm9Ly9Y7RP3QPyQUQBLqv04Cc3jgiMbUQYU8,1359
18
+ corelle/engine/query/rotation-pairs-for-time.sql,sha256=Jyl8OdmFLMbNrPKNO0zQlYPnVgemH2Hy8XIDtA8SLYg,1316
19
+ corelle/engine/query/rotation-pairs.sql,sha256=4zgdtK_Z23TnnCD3NJgjguG0hGU3E1lkCp3jROI_P8U,1343
20
+ corelle/engine/query/update-cache.sql,sha256=7qC-rGjRZf-ocPaeCdUr_wqxHlq52S7dp8wvx_kb64Y,383
21
+ corelle/engine/rotate.py,sha256=evTChWxcCvy8w7e38YI8kHu5U39P6CqzvUYSLFH44pA,7137
22
+ corelle/engine/schema/00-init.sql,sha256=tVZAyi9mAJ02Rua0eufq6S2wjJ8hZvevz8-yLoghN9Y,77
23
+ corelle/engine/schema/01-schema.sql,sha256=Tj2TFjQT9RgzN1reU0rx1awyTx6BSwS6TcIYDWKnoJ0,2502
24
+ corelle/engine/schema/02-functions.sql,sha256=o6uJBaPY9lsU9y_2nhIrP8emYzjmt0z_gBgh60QHb98,6534
25
+ corelle/engine/schema/03-testing-functions.sql,sha256=rzFivenOweJSWzHUV46fkaPnZO3Beyyx5rOHvClmfjg,5591
26
+ corelle/engine/schema/04-views.sql,sha256=uQC2AHnsPEevMvm3pZUXXcCpVLO3j1x7iqF1KgJAZwk,855
27
+ corelle/engine/storage.py,sha256=ngTGd3Wjadib6WRNZiKGNNYuLZHObGe6LcMQEKM9mhM,309
28
+ corelle_engine-3.0.0.dist-info/WHEEL,sha256=3OmCxFA0ffBIsX4x0o8CdfSvZAOvO3mzEG8U_z5TvV4,80
29
+ corelle_engine-3.0.0.dist-info/entry_points.txt,sha256=2lP8_vn_kszBAcQkxmn92i-Z2LqUx-0SG39M22tdSjw,48
30
+ corelle_engine-3.0.0.dist-info/METADATA,sha256=MOyLyMX-1k01L4Pd9pMUr_3m6tdz3nll0adX6O15PDU,1215
31
+ corelle_engine-3.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.13.8
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ corelle = corelle.engine:cli
3
+