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.
- corelle/engine/__init__.py +1 -0
- corelle/engine/cache.py +78 -0
- corelle/engine/cli.py +188 -0
- corelle/engine/database.py +35 -0
- corelle/engine/load_data.py +350 -0
- corelle/engine/query/__init__.py +7 -0
- corelle/engine/query/active-plates-at-time.sql +11 -0
- corelle/engine/query/cache-feature-dataset.sql +37 -0
- corelle/engine/query/delete-extraneous-cache.sql +7 -0
- corelle/engine/query/feature-dataset-cached.sql +4 -0
- corelle/engine/query/feature-dataset.sql +21 -0
- corelle/engine/query/modern-plate-polygons-cached.sql +3 -0
- corelle/engine/query/modern-plate-polygons.sql +14 -0
- corelle/engine/query/plate-for-point.sql +7 -0
- corelle/engine/query/plate-time-ranges.sql +9 -0
- corelle/engine/query/plates-for-model.sql +6 -0
- corelle/engine/query/rotation-pairs-for-model.sql +64 -0
- corelle/engine/query/rotation-pairs-for-time.sql +63 -0
- corelle/engine/query/rotation-pairs.sql +64 -0
- corelle/engine/query/update-cache.sql +9 -0
- corelle/engine/rotate.py +265 -0
- corelle/engine/schema/00-init.sql +2 -0
- corelle/engine/schema/01-schema.sql +88 -0
- corelle/engine/schema/02-functions.sql +233 -0
- corelle/engine/schema/03-testing-functions.sql +186 -0
- corelle/engine/schema/04-views.sql +47 -0
- corelle/engine/storage.py +11 -0
- corelle_engine-3.0.0.dist-info/METADATA +31 -0
- corelle_engine-3.0.0.dist-info/RECORD +31 -0
- corelle_engine-3.0.0.dist-info/WHEEL +4 -0
- corelle_engine-3.0.0.dist-info/entry_points.txt +3 -0
|
@@ -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,,
|