diff --git a/_albion.sql b/_albion.sql
index a35baa7..2e56925 100644
--- a/_albion.sql
+++ b/_albion.sql
@@ -32,50 +32,40 @@ create table _albion.metadata(
snap_distance real not null default 1,
precision real default .01,
interpolation interpolation_method default 'balanced_tangential',
- end_distance real default 25,
- end_angle real default 5.0,
correlation_distance real default 200,
correlation_angle real default 5.0,
- parent_correlation_angle real default 1.0)
+ parent_correlation_angle real default 1.0,
+ end_node_relative_distance real default .3,
+ end_node_relative_thickness real default .3,
+ version varchar)
;
-insert into _albion.metadata(srid) select $SRID
+insert into _albion.metadata(srid, version) select $SRID, '2.0'
;
-create table _albion.collar(
- id varchar primary key default _albion.unique_id()::varchar,
- x double precision,
- y double precision,
- z real,
- date_ varchar,
- geom geometry('POINTZ', $SRID),
- comments varchar)
-;
-
-create index collar_geom_idx on _albion.collar using gist(geom)
+create table _albion.layer(
+ name varchar primary key,
+ fields_definition text not null)
;
create table _albion.hole(
- id varchar primary key,
- collar_id varchar unique not null references _albion.collar(id) on delete cascade on update cascade,
- depth_ real,
+ id varchar primary key default _albion.unique_id()::varchar,
+ date_ varchar,
+ depth_ real not null,
+ check(depth_ > 0),
+ x double precision not null,
+ y double precision not null,
+ z double precision not null,
+ comments varchar,
geom geometry('LINESTRINGZ', $SRID))
;
-create index hole_geom_idx on _albion.hole using gist(geom)
+alter table _albion.hole add constraint hole_geom_length_chk check (geom is null or abs(st_3dlength(geom) - depth_) <= 1e-3)
;
-create index hole_collar_id_idx on _albion.hole(collar_id)
-;
-
-
-alter table _albion.hole alter column id set default _albion.unique_id()::varchar
+create index hole_geom_idx on _albion.hole using gist(geom)
;
--------------------------------------------------------------------------------
--- MEASURES
--------------------------------------------------------------------------------
-
create table _albion.deviation(
hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
from_ real,
@@ -83,147 +73,13 @@ create table _albion.deviation(
azimuth real)
;
-create index deviation_hole_id_idx on _albion.deviation(hole_id)
-;
-
-create table _albion.radiometry(
- id varchar primary key,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- from_ real,
- to_ real,
- gamma real,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-create index radiometry_geom_idx on _albion.radiometry using gist(geom)
-;
-
-create index radiometry_hole_id_idx on _albion.radiometry(hole_id)
-;
-
-alter table _albion.radiometry alter column id set default _albion.unique_id()::varchar
-;
-
-create table _albion.resistivity(
- id varchar primary key,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- from_ real,
- to_ real,
- rho real,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-create index resistivity_geom_idx on _albion.resistivity using gist(geom)
-;
-
-create index resistivity_hole_id_idx on _albion.resistivity(hole_id)
-;
-
-alter table _albion.resistivity alter column id set default _albion.unique_id()::varchar
-;
-
-
-create table _albion.formation(
- id varchar primary key,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- from_ real,
- to_ real,
- code integer,
- comments varchar,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-create index formation_geom_idx on _albion.formation using gist(geom)
-;
-
-create index formation_hole_id_idx on _albion.formation(hole_id)
-;
-
-alter table _albion.formation alter column id set default _albion.unique_id()::varchar
-;
-
-create table _albion.lithology(
- id varchar primary key,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- from_ real,
- to_ real,
- code integer,
- comments varchar,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-create index lithology_geom_idx on _albion.lithology using gist(geom)
-;
-
-create index lithology_hole_id_idx on _albion.lithology(hole_id)
-;
-
-alter table _albion.lithology alter column id set default _albion.unique_id()::varchar
-;
-
-create table _albion.facies(
- id varchar primary key,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- from_ real,
- to_ real,
- code integer,
- comments varchar,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-create index facies_geom_idx on _albion.facies using gist(geom)
-;
-
-create index facies_hole_id_idx on _albion.facies(hole_id)
-;
-
-alter table _albion.facies alter column id set default _albion.unique_id()::varchar
-;
-
-create table _albion.chemical(
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- from_ real,
- to_ real,
- num_sample varchar,
- element varchar,
- thickness real,
- gt real, -- thickness * grade
- grade real,
- equi real,
- comments varchar)
-;
-
-create index chemical_hole_id_idx on _albion.chemical(hole_id)
-;
-
-create table _albion.mineralization(
- id varchar primary key,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- level_ real,
- from_ real,
- to_ real,
- oc real,
- accu real,
- grade real,
- comments varchar,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-create index mineralization_geom_idx on _albion.mineralization using gist(geom)
-;
-
-create index mineralization_hole_id_idx on _albion.mineralization(hole_id)
-;
-
-alter table _albion.mineralization alter column id set default _albion.unique_id()::varchar
-;
-------------------------------------------------------------------------------
-- GRAPH
-------------------------------------------------------------------------------
create table _albion.node(
- id varchar primary key,
+ id varchar primary key default _albion.unique_id()::varchar,
graph_id varchar not null references _albion.graph(id) on delete cascade on update cascade,
unique(id, graph_id),
hole_id varchar references _albion.hole(id) on delete cascade,
@@ -243,11 +99,8 @@ create index node_graph_id_idx on _albion.node(graph_id)
create index node_hole_id_idx on _albion.node(hole_id)
;
-alter table _albion.node alter column id set default _albion.unique_id()::varchar
-;
-
create table _albion.edge(
- id varchar primary key,
+ id varchar primary key default _albion.unique_id()::varchar,
start_ varchar not null ,
foreign key (graph_id, start_) references _albion.node(graph_id, id) on delete cascade on update cascade,
end_ varchar not null,
@@ -271,14 +124,11 @@ create index edge_start__idx on _albion.edge(start_)
create index edge_end__idx on _albion.edge(end_)
;
-alter table _albion.edge alter column id set default _albion.unique_id()::varchar
-;
-
create table _albion.cell(
- id varchar primary key,
- a varchar not null references _albion.collar(id) on delete cascade on update cascade,
- b varchar not null references _albion.collar(id) on delete cascade on update cascade,
- c varchar not null references _albion.collar(id) on delete cascade on update cascade,
+ id varchar primary key default _albion.unique_id()::varchar,
+ a varchar not null references _albion.hole(id) on delete cascade on update cascade,
+ b varchar not null references _albion.hole(id) on delete cascade on update cascade,
+ c varchar not null references _albion.hole(id) on delete cascade on update cascade,
geom geometry('POLYGON', $SRID) not null check(st_isvalid(geom) and st_numpoints(geom)=4)
)
;
@@ -295,32 +145,29 @@ create index volume_cell_b_idx on _albion.cell(b)
create index volume_cell_c_idx on _albion.cell(c)
;
-alter table _albion.cell alter column id set default _albion.unique_id()::varchar
-;
-
create table _albion.group(
id integer primary key
)
;
create table _albion.section(
- id varchar primary key,
+ id varchar primary key default _albion.unique_id()::varchar,
anchor geometry('LINESTRING', $SRID) not null check(st_numpoints(anchor)=2),
- geom geometry('LINESTRING', $SRID) not null,
- scale real not null default 1,
- group_id integer references _albion.group(id) on delete set null on update cascade
+ geom geometry('MULTILINESTRING', $SRID),
+ scale real not null default 1
)
;
-alter table _albion.section alter column id set default _albion.unique_id()::varchar
-;
-
create table _albion.volume(
- id varchar primary key,
+ id varchar primary key default _albion.unique_id()::varchar,
graph_id varchar not null references _albion.graph(id) on delete cascade on update cascade,
cell_id varchar not null references _albion.cell(id) on delete cascade on update cascade,
- triangulation geometry('MULTIPOLYGONZ', $SRID) not null
-);
+ triangulation geometry('MULTIPOLYGONZ', $SRID) not null,
+ face1 geometry('MULTIPOLYGONZ', $SRID),
+ face2 geometry('MULTIPOLYGONZ', $SRID),
+ face3 geometry('MULTIPOLYGONZ', $SRID)
+)
+;
create index volume_graph_id_idx on _albion.volume(graph_id)
;
@@ -328,9 +175,6 @@ create index volume_graph_id_idx on _albion.volume(graph_id)
create index volume_cell_id_idx on _albion.volume(cell_id)
;
-alter table _albion.volume alter column id set default _albion.unique_id()::varchar
-;
-
create table _albion.group_cell(
group_id integer not null references _albion.group(id) on delete cascade on update cascade,
cell_id varchar not null references _albion.cell(id) on delete cascade on update cascade,
@@ -347,10 +191,10 @@ create index group_cell_groupe_id_idx on _albion.group_cell(group_id)
create table _albion.end_node(
- id varchar primary key,
+ id varchar primary key default _albion.unique_id()::varchar,
geom geometry('LINESTRINGZ', $SRID) not null check (st_numpoints(geom)=2),
node_id varchar not null references _albion.node(id) on delete cascade on update cascade,
- collar_id varchar not null references _albion.collar(id) on delete cascade on update cascade,
+ hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
graph_id varchar references _albion.graph(id) on delete cascade
)
;
@@ -358,35 +202,22 @@ create table _albion.end_node(
create index end_node_geom_idx on _albion.end_node using gist(geom)
;
-alter table _albion.end_node alter column id set default _albion.unique_id()::varchar
-;
-
---create table _albion.end_edge(
--- id varchar primary key,
--- start_ varchar not null ,
--- foreign key (graph_id, start_) references _albion.end_node(graph_id, id) on delete cascade on update cascade,
--- end_ varchar not null,
--- foreign key (graph_id, end_) references _albion.end_node(graph_id, id) on delete cascade on update cascade,
--- unique (start_, end_),
--- check (start_ < end_),
--- graph_id varchar references _albion.graph(id) on delete cascade,
--- geom geometry('LINESTRINGZ', $SRID) not null check (st_isvalid(geom))
---)
---;
---
---create index end_edge_geom_idx on _albion.end_edge using gist(geom)
---;
---
---create index end_edge_graph_id_idx on _albion.end_edge(graph_id)
---;
---
---create index end_edge_start__idx on _albion.end_edge(start_)
---;
---
---create index end_edge_end__idx on _albion.end_edge(end_)
---;
---
---alter table _albion.end_edge alter column id set default _albion.unique_id()::varchar
---;
+create table _albion.named_section(
+ id varchar primary key default _albion.unique_id()::varchar,
+ geom geometry('LINESTRING', $SRID) not null,
+ cut geometry('MULTILINESTRING', $SRID) not null,
+ section varchar not null references _albion.section(id) on delete cascade on update cascade
+)
+;
+
+create table _albion.vertical_face(
+ id varchar primary key default _albion.unique_id()::varchar,
+ graph_id varchar not null references _albion.graph(id) on delete cascade on update cascade,
+ left_hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
+ right_hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
+ triangulation geometry('MULTIPOLYGONZ', $SRID) not null
+);
+
+
diff --git a/_albion_table.sql b/_albion_table.sql
new file mode 100644
index 0000000..53014c4
--- /dev/null
+++ b/_albion_table.sql
@@ -0,0 +1,10 @@
+create table _albion.$NAME(
+ id varchar primary key default _albion.unique_id()::varchar,
+ hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
+ from_ real check (from_>=0),
+ to_ real check (to_>=0),
+ ${FIELDS_DEFINITION})
+;
+
+insert into _albion.layer(name, fields_definition) values ('$NAME', '$FIELDS_DEFINITION')
+;
diff --git a/_albion_v1_to_v2.sql b/_albion_v1_to_v2.sql
new file mode 100644
index 0000000..2d4456d
--- /dev/null
+++ b/_albion_v1_to_v2.sql
@@ -0,0 +1,113 @@
+-- changed metadata
+alter table _albion.metadata drop column end_angle
+;
+alter table _albion.metadata drop column end_distance
+;
+alter table _albion.metadata add column end_node_relative_distance real default .3
+;
+alter table _albion.metadata add column version varchar default '2.0'
+;
+alter table _albion.metadata add column end_node_relative_thickness real default .3
+;
+
+-- add layer table
+create table _albion.layer(
+ name varchar primary key,
+ fields_definition text not null)
+;
+
+insert into _albion.layer(name, fields_definition)
+select t.name, t.fields_definition
+from (VALUES
+ ('radiometry', 'gamma real'),
+ ('resistivity', 'rho real'),
+ ('formation', 'code integer, comments varchar'),
+ ('lithology', 'code integer, comments varchar'),
+ ('facies', 'code integer, comments varchar'),
+ ('chemical', 'num_sample varchar, element varchar, thickness real, gt real, grade real, equi real, comments varchar'),
+ ('mineralization', 'level_ real, oc real, accu real, grade real, comments varchar')
+ ) as t(name, fields_definition)
+join information_schema.tables on table_schema = '_albion' and table_name = t.name
+;
+
+alter table if exists _albion.chemical add column id varchar primary key default _albion.unique_id()::varchar
+;
+
+-- merge collar and hole tables
+alter table _albion.hole alter column id set default _albion.unique_id()::varchar
+;
+alter table _albion.hole add column date_ varchar
+;
+alter table _albion.hole add constraint depth_check check(depth_ > 0)
+;
+alter table _albion.hole add column x double precision
+;
+alter table _albion.hole add column y double precision
+;
+alter table _albion.hole add column z double precision
+;
+alter table _albion.hole add column comments varchar
+;
+update _albion.hole as h set x=c.x, y=c.y, z=c.z, date_=c.date_, comments=c.comments
+from _albion.collar as c where h.collar_id=c.id
+;
+alter table _albion.hole alter column x set not null
+;
+alter table _albion.hole alter column y set not null
+;
+alter table _albion.hole alter column z set not null
+;
+alter table _albion.hole drop column collar_id
+;
+alter table _albion.hole add constraint hole_geom_length_chk check (geom is null or abs(st_3dlength(geom) - depth_) <= 1e-3)
+;
+
+-- cell now references holes rather than collar
+alter table _albion.cell drop constraint cell_a_fkey
+;
+alter table _albion.cell drop constraint cell_b_fkey
+;
+alter table _albion.cell drop constraint cell_c_fkey
+;
+alter table _albion.cell add constraint cell_a_fkey foreign key(a) REFERENCES _albion.hole(id);
+;
+alter table _albion.cell add constraint cell_b_fkey foreign key(b) REFERENCES _albion.hole(id);
+;
+alter table _albion.cell add constraint cell_c_fkey foreign key(c) REFERENCES _albion.hole(id);
+;
+
+-- change section
+alter table _albion.section alter column geom type geometry('MULTILINESTRING', $SRID) using st_multi(geom)
+;
+alter table _albion.section drop column group_id
+;
+
+-- end_node now reference hole rather than collar
+alter table _albion.end_node drop constraint end_node_collar_id_fkey;
+;
+alter table _albion.end_node rename column collar_id to hole_id
+;
+alter table _albion.end_node add constraint end_node_hole_id_fkey foreign key(hole_id) REFERENCES _albion.hole(id);
+;
+
+drop table _albion.collar
+;
+
+alter table _albion.volume add column face1 geometry('MULTIPOLYGONZ', $SRID)
+;
+
+alter table _albion.volume add column face2 geometry('MULTIPOLYGONZ', $SRID)
+;
+
+alter table _albion.volume add column face3 geometry('MULTIPOLYGONZ', $SRID)
+;
+
+-- adds named_section
+create table _albion.named_section(
+ id varchar primary key default _albion.unique_id()::varchar,
+ geom geometry('LINESTRING', $SRID) not null,
+ cut geometry('MULTILINESTRING', $SRID) not null,
+ section varchar not null references _albion.section(id) on delete cascade on update cascade
+)
+;
+
diff --git a/albion.sql b/albion.sql
index 7d915f3..d04fd1a 100644
--- a/albion.sql
+++ b/albion.sql
@@ -8,61 +8,27 @@ create schema albion
-------------------------------------------------------------------------------
-- UTILITY FUNCTIONS
-------------------------------------------------------------------------------
---create or replace function public.st_3dlineinterpolatepoint(line_ geometry, sigma_ float)
---returns geometry
---language plpython3u immutable
---as
---$$
---
--- from shapely import wkb
--- from shapely import geos
--- from shapely.geometry import Point
--- import numpy as np
--- from numpy import array
--- from numpy.linalg import norm
--- geos.WKBWriter.defaults['include_srid'] = True
---
--- if line_ is None:
--- return None
---
--- assert(sigma_ >=0 and sigma_ <=1)
---
--- line = wkb.loads(bytes.fromhex(line_))
---
--- if sigma_ > 0 and sigma_ < 1:
--- l = array(line.coords)
--- seg = l[:-1] - l[1:]
--- seg_length = np.sum(seg**2,axis=-1)**.5
--- line_length = np.sum(seg_length)
--- target_length = line_length*sigma_
--- cum_length = np.cumsum(seg_length)
--- idx = np.searchsorted(np.cumsum(seg_length), target_length)
--- overshoot = cum_length[idx] - target_length
--- a = overshoot/seg_length[idx]
--- result = Point(l[idx]*a + l[idx+1]*(1.-a))
---
--- elif sigma_ == 1:
--- result = Point(line.coords[-1])
---
--- elif sigma_ == 0:
--- result = Point(line.coords[0])
---
--- geos.lgeos.GEOSSetSRID(result._geom, geos.lgeos.GEOSGetSRID(line._geom))
--- return result.wkb_hex
---
---$$
---;
---create or replace function albion.srid()
---returns integer
---language plpgsql stable
---as
---$$
--- begin
--- return select (srid from _albion.metadata);
--- end;
---$$
---;
+create or replace function albion.triangle_aspect_ratio(geom geometry)
+returns float
+language plpgsql
+as
+$$
+ declare
+ a float;
+ b float;
+ c float;
+ s float;
+ begin
+ a := st_distance(st_pointn(st_exteriorring(geom), 1), st_pointn(st_exteriorring(geom), 2));
+ b := st_distance(st_pointn(st_exteriorring(geom), 2), st_pointn(st_exteriorring(geom), 3));
+ c := st_distance(st_pointn(st_exteriorring(geom), 3), st_pointn(st_exteriorring(geom), 1));
+ s := (a+b+c)/2;
+ return a*b*c/(8*(s-a)*(s-b)*(s-c));
+
+ end;
+$$
+;
create or replace function albion.hole_geom(hole_id_ varchar)
returns geometry
@@ -72,13 +38,15 @@ $$
declare
depth_max_ real;
hole_geom_ geometry;
- collar_id_ varchar;
+ x_ double precision;
+ y_ double precision;
+ z_ double precision;
collar_geom_ geometry;
+ path_ varchar;
begin
- select collar_id, depth_ from albion.hole where id=hole_id_ into collar_id_, depth_max_;
-
- select geom from albion.collar where id=collar_id_ into collar_geom_;
+ select x, y, z, depth_ from _albion.hole where id=hole_id_ into x_, y_, z_, depth_max_;
+ collar_geom_ := st_setsrid(st_makepoint(x_, y_, z_), $SRID);
with dz as (
select
from_ as md2, coalesce(lag(from_) over w, 0) as md1,
@@ -91,9 +59,9 @@ $$
),
pt as (
select md2, wd2, haz2,
- st_x(collar_geom_) + sum(0.5 * (md2 - md1) * (sin(wd1) * sin(haz1) + sin(wd2) * sin(haz2))) over w as x,
- st_y(collar_geom_) + sum(0.5 * (md2 - md1) * (sin(wd1) * cos(haz1) + sin(wd2) * cos(haz2))) over w as y,
- st_z(collar_geom_) - sum(0.5 * (md2 - md1) * (cos(wd2) + cos(wd1))) over w as z
+ x_ + sum(0.5 * (md2 - md1) * (sin(wd1) * sin(haz1) + sin(wd2) * sin(haz2))) over w as x,
+ y_ + sum(0.5 * (md2 - md1) * (sin(wd1) * cos(haz1) + sin(wd2) * cos(haz2))) over w as y,
+ z_ - sum(0.5 * (md2 - md1) * (cos(wd2) + cos(wd1))) over w as z
from dz
window w AS (order by md1)
),
@@ -106,6 +74,7 @@ $$
into hole_geom_;
if hole_geom_ is not null and st_3dlength(hole_geom_) < depth_max_ and st_3dlength(hole_geom_) > 0 then
+ path_ := 'too short';
-- holes is not long enough
with last_segment as (
select st_pointn(hole_geom_, st_numpoints(hole_geom_)-1) as start_, st_endpoint(hole_geom_) as end_
@@ -128,9 +97,13 @@ $$
-- hole have no deviation
elsif hole_geom_ is null or st_3dlength(hole_geom_) = 0 then
+ path_ := 'no length';
select st_makeline( collar_geom_, st_translate(collar_geom_, 0, 0, -depth_max_)) into hole_geom_;
end if;
+ if abs(st_3dlength(hole_geom_) - depth_max_) > 1e-3 then
+ raise 'hole %s %s %s %', hole_id_, depth_max_, st_3dlength(hole_geom_), path_;
+ end if;
return hole_geom_;
end;
$$
@@ -144,45 +117,64 @@ $$
begin
return (
select st_makeline(
- st_3dlineinterpolatepoint(geom, from_/depth_),
- st_3dlineinterpolatepoint(geom, to_/depth_))
- from albion.hole where id=hole_id_
+ st_3dlineinterpolatepoint(geom, least(from_/l, 1)),
+ st_3dlineinterpolatepoint(geom, least(to_/l, 1)))
+ from (select geom, st_3dlength(geom) as l from albion.hole where id=hole_id_) as t
);
end;
$$
;
-create view albion.collar as select id, geom, date_, comments from _albion.collar
+create or replace view albion.collar as select id, st_startpoint(geom)::geometry('POINTZ', $SRID) as geom, date_, comments, depth_ from _albion.hole
;
-create view albion.metadata as select id, srid, close_collar_distance, snap_distance, precision, interpolation, end_distance, end_angle, correlation_distance, correlation_angle, parent_correlation_angle from _albion.metadata
+alter view albion.collar alter id set default _albion.unique_id()::varchar
;
-create view albion.hole as select id, collar_id, depth_, geom::geometry('LINESTRINGZ', $SRID) from _albion.hole
-;
-
-create view albion.deviation as select hole_id, from_, dip, azimuth from _albion.deviation
-;
-
-create view albion.formation as select id, hole_id, from_, to_, code, comments, geom::geometry('LINESTRINGZ', $SRID) from _albion.formation
-;
+create or replace function albion.collar_instead_fct()
+returns trigger
+language plpgsql
+as
+$$
+ begin
+ if tg_op in ('INSERT', 'UPDATE') then
+ new.date_ := coalesce(new.date_, now()::date::varchar);
+ end if;
-create view albion.resistivity as select id, hole_id, from_, to_, rho, geom::geometry('LINESTRINGZ', $SRID) from _albion.resistivity
+ if tg_op = 'INSERT' then
+ insert into _albion.hole(id, date_, depth_, x, y, z, comments)
+ values(new.id, new.date_, new.depth_, st_x(new.geom), st_y(new.geom), st_z(new.geom), new.comments)
+ returning id into new.id;
+ update _albion.hole set geom = albion.hole_geom(new.id) where id=new.id;
+ return new;
+ elsif tg_op = 'UPDATE' then
+ update _albion.hole set id=new.id, date_=new.date_, depth_=new.depth_, x=st_x(new.geom), y=st_y(new.geom), z=st_z(new.geom), comments=new.comments
+ where id=old.id;
+ update _albion.hole set geom = albion.hole_geom(new.id) where id=new.id;
+ return new;
+ elsif tg_op = 'DELETE' then
+ delete from _albion.collar where id=old.id;
+ return old;
+ end if;
+ end;
+$$
;
-create view albion.radiometry as select id, hole_id, from_, to_, gamma, geom::geometry('LINESTRINGZ', $SRID) from _albion.radiometry
+create trigger collar_instead_trig
+ instead of insert or update or delete on albion.collar
+ for each row execute procedure albion.collar_instead_fct()
;
-create view albion.lithology as select id, hole_id, from_, to_, code, comments, geom::geometry('LINESTRINGZ', $SRID) from _albion.lithology
+create view albion.metadata as select id, srid, close_collar_distance, snap_distance, precision, interpolation, end_node_relative_distance, end_node_relative_thickness, correlation_distance, correlation_angle, parent_correlation_angle from _albion.metadata
;
-create view albion.facies as select id, hole_id, from_, to_, code, comments, geom::geometry('LINESTRINGZ', $SRID) from _albion.facies
+create view albion.layer as select name, fields_definition from _albion.layer
;
-create view albion.chemical as select hole_id, from_, to_, num_sample, element, thickness, gt, grade, equi, comments from _albion.chemical
+create view albion.hole as select id, depth_, geom::geometry('LINESTRINGZ', $SRID) from _albion.hole
;
-create view albion.mineralization as select id, hole_id, level_, from_, to_, oc, accu, grade, geom::geometry('LINESTRINGZ', $SRID) from _albion.mineralization
+create view albion.deviation as select hole_id, from_, dip, azimuth from _albion.deviation
;
create or replace view albion.graph as
@@ -213,6 +205,8 @@ $$
end if;
end if;
+ new.geom := coalesce(new.geom, albion.hole_piece(new.from_, new.to_, new.hole_id));
+
if tg_op = 'INSERT' then
insert into _albion.node(id, graph_id, hole_id, from_, to_, geom, parent)
values(new.id, new.graph_id, new.hole_id, new.from_, new.to_, new.geom, new.parent)
@@ -239,11 +233,52 @@ create trigger node_instead_trig
create or replace view albion.close_collar as
-select a.id, a.geom from _albion.collar as a, _albion.collar as b, _albion.metadata as m
+select distinct on (a.id) a.id, a.geom from albion.collar as a, albion.collar as b, _albion.metadata as m
where a.id != b.id and st_dwithin(a.geom, b.geom, m.close_collar_distance)
;
-create view albion.cell as select id, a, b, c, geom::geometry('POLYGON', $SRID) from _albion.cell
+create view albion.cell as select id, a, b, c, geom::geometry('POLYGON', $SRID), albion.triangle_aspect_ratio(geom) as aspect_ratio from _albion.cell
+;
+
+create or replace function albion.cell_after_fct()
+returns trigger
+language plpgsql
+as
+$$
+ begin
+ refresh materialized view albion.all_edge;
+ return null;
+ end;
+$$
+;
+
+-- this trigger should work on the view instead of the table, but for unknown reason it doesn't, so we put it on the table
+drop trigger if exists cell_after_trig ON _albion.cell
+;
+
+create trigger cell_after_trig
+ after delete on _albion.cell
+ for each statement execute procedure albion.cell_after_fct()
+;
+
+create or replace function albion.tesselate(polygon_ geometry, lines_ geometry, points_ geometry)
+returns geometry
+language plpython3u volatile
+as
+$$
+ from shapely import wkb
+ from shapely import geos
+ geos.WKBWriter.defaults['include_srid'] = True
+ from fourmy import tessellate
+
+ polygon = wkb.loads(bytes.fromhex(polygon_))
+ lines = wkb.loads(bytes.fromhex(lines_)) if lines_ else None
+ points = wkb.loads(bytes.fromhex(points_)) if points_ else None
+ result = tessellate(polygon, lines, points)
+
+ geos.lgeos.GEOSSetSRID(result._geom, geos.lgeos.GEOSGetSRID(polygon._geom))
+ return result.wkb_hex
+$$
;
create or replace function albion.triangulate()
@@ -255,18 +290,24 @@ $$
delete from _albion.cell;
insert into _albion.cell(a, b, c, geom)
with cell as (
- select ST_DelaunayTriangles(ST_Collect(ST_Force2D(geom))) as geom from _albion.collar
+ select albion.tesselate(
+ st_convexhull((select st_collect(st_force2d(geom)) from albion.collar)),
+ st_multi((select st_collectionhomogenize(st_collect(cut)) from albion.named_section)),
+ st_multi((select st_collect(st_force2d(geom)) from albion.collar))
+ ) as geom
),
splt as (
select (ST_Dump(geom)).geom from cell
)
select
- (select c.id from _albion.collar as c where st_intersects(c.geom, st_pointn(st_exteriorring(s.geom), 1))),
- (select c.id from _albion.collar as c where st_intersects(c.geom, st_pointn(st_exteriorring(s.geom), 2))),
- (select c.id from _albion.collar as c where st_intersects(c.geom, st_pointn(st_exteriorring(s.geom), 3))),
+ (select c.id from albion.collar as c where st_intersects(c.geom, st_pointn(st_exteriorring(s.geom), 1))),
+ (select c.id from albion.collar as c where st_intersects(c.geom, st_pointn(st_exteriorring(s.geom), 2))),
+ (select c.id from albion.collar as c where st_intersects(c.geom, st_pointn(st_exteriorring(s.geom), 3))),
s.geom
from splt as s;
+ refresh materialized view albion.all_edge;
+
return (select count(1) from _albion.cell);
end;
$$
@@ -292,39 +333,6 @@ $$
$$
;
--- contour of the cells that face the line
-create or replace function albion.first_section(anchor geometry)
-returns geometry
-language plpgsql stable
-as
-$$
- begin
- return (
- with hull as (
- select st_exteriorring(st_unaryunion(st_collect(geom))) as geom from _albion.cell
- ),
- seg as (
- select ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp, ST_PointN(geom, generate_series(2, ST_NPoints(geom) )) as ep
- from hull
- ),
- facing as (
- select st_force2d(st_makeline(sp, ep)) as geom
- from seg
- where -albion.cos_angle(anchor, sp, ep) > cos(60*pi()/180)
- ),
- merged as (
- select st_linemerge(st_collect(geom)) as geom from facing
- ),
- sorted as (
- select rank() over(order by st_length(geom) desc) as rk, geom
- from (select (st_dump(geom)).geom from merged) as t
- )
- select geom from sorted where rk=1
- );
- end;
-$$
-;
-
create or replace function albion.is_touchingrightside(line geometry, poly geometry)
returns boolean
language plpgsql immutable
@@ -390,7 +398,7 @@ select albion.is_touchingrightside('LINESTRING(327627.06 2079630.27,327229.65 20
;
--- triangle is visible if points are on the line, or by removing the trinagle edge that touch
+-- polygon is visible if points are on the line, or by removing the edge that touches
-- the line, the line of sight from anchor to point doesn't cross the line
create or replace function albion.is_visible(anchor geometry, section geometry, poly geometry)
returns boolean
@@ -401,24 +409,30 @@ $$
nb_visible integer;
ring geometry;
occluder geometry;
+ point_on_poly geometry;
line_od_sight geometry;
begin
nb_visible := 0;
ring := st_exteriorring(poly);
- for i in 1..st_numpoints(ring) loop
- if st_intersects(section, st_pointn(ring, i)) then
- nb_visible := nb_visible + 1;
- else
- occluder := coalesce(occluder, st_difference(section, ring));
- line_od_sight := st_makeline(st_closestpoint(anchor, st_pointn(ring, i)), st_pointn(ring, i));
- --raise notice 'occluder %', st_astext(occluder);
- --raise notice 'los %', st_astext(line_od_sight);
- if not st_intersects(line_od_sight, occluder) then
+ occluder := st_difference(section, ring);
+ if occluder is not null then
+ for i in 1..st_numpoints(ring) loop
+ if st_intersects(section, st_pointn(ring, i)) then
nb_visible := nb_visible + 1;
+ else
+ line_od_sight := st_makeline(st_closestpoint(anchor, st_pointn(ring, i)), st_pointn(ring, i));
+ --raise notice 'occluder %', st_astext(occluder);
+ --raise notice 'los %', st_astext(line_od_sight);
+ if not st_intersects(line_od_sight, occluder) then
+ nb_visible := nb_visible + 1;
+ end if;
end if;
- end if;
- end loop;
- return nb_visible = st_numpoints(ring);
+ end loop;
+ end if;
+ -- we also check that the line between a point on surface and the anchor crosses the section (we are looking "away" from anchor)
+ point_on_poly := st_pointonsurface(poly);
+ line_od_sight := st_makeline(st_closestpoint(anchor, point_on_poly), point_on_poly);
+ return nb_visible = st_numpoints(ring) and st_intersects(line_od_sight, section);
end;
$$
;
@@ -457,7 +471,7 @@ $$
$$
;
-create view albion.section as select id, scale, group_id, anchor::geometry('LINESTRING', $SRID), geom::geometry('LINESTRING', $SRID)
+create view albion.section as select id, scale, anchor::geometry('LINESTRING', $SRID), geom::geometry('MULTILINESTRING', $SRID)
from _albion.section
;
@@ -474,12 +488,12 @@ as
$$
begin
if tg_op = 'INSERT' then
- insert into _albion.section(id, anchor, geom, scale, group_id)
- values(new.id, new.anchor, coalesce(new.geom, albion.first_section(new.anchor)), new.scale, new.group_id)
+ insert into _albion.section(id, anchor, geom, scale)
+ values(new.id, new.anchor, new.geom, new.scale)
returning id, geom into new.id, new.geom;
return new;
elsif tg_op = 'UPDATE' then
- update _albion.section set id=new.id, anchor=new.anchor, geom=new.geom, scale=new.scale, group_id=new.group_id
+ update _albion.section set id=new.id, anchor=new.anchor, geom=new.geom, scale=new.scale
where id=old.id;
return new;
elsif tg_op = 'DELETE' then
@@ -496,24 +510,10 @@ create trigger section_instead_trig
;
-create or replace function albion.next_group()
-returns integer
-language plpgsql stable
-as
-$$
- begin
- return (select coalesce(max(id), 0) + 1 from _albion.group);
- end;
-$$
-;
-
create view albion.group as
select id from _albion.group
;
-alter view albion.group alter column id set default albion.next_group()
-;
-
create view albion.group_cell as
select gc.section_id || ' ' || gc.cell_id as id, gc.cell_id, c.geom, gc.group_id, gc.section_id
from _albion.cell as c
@@ -546,40 +546,6 @@ create trigger group_cell_instead_trig
for each row execute procedure albion.group_cell_instead_fct()
;
-create view albion.current_section as
-with hull as (
- select st_unaryunion(st_collect(c.geom)) as geom, gc.section_id
- from _albion.cell as c
- join _albion.group_cell as gc on gc.cell_id=c.id
- group by gc.section_id
-),
-hull_contour as (
- select st_exteriorring(geom) as geom, section_id from hull
-),
-seg as (
- select ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp, ST_PointN(geom, generate_series(2, ST_NPoints(geom) )) as ep, section_id
- from hull_contour
-),
-facing as (
- select st_force2d(st_makeline(seg.sp, seg.ep)) as geom, seg.section_id
- from seg join _albion.section as s on s.id = seg.section_id
- where albion.cos_angle(s.anchor, seg.sp, seg.ep) > cos(89*pi()/180)
-),
-merged as (
- select st_linemerge(st_collect(facing.geom)) as geom, section_id
- from facing join _albion.section as s on s.id = facing.section_id
- group by section_id, s.geom
-),
-sorted as (
- select rank() over(partition by section_id order by st_length(geom) desc) as rk, geom, section_id
- from (select (st_dump(geom)).geom, section_id from merged) as t
-)
-select section_id as id, st_reverse(geom)::geometry('LINESTRING', $SRID) as geom from sorted where rk=1
-union all
-select s.id, (albion.first_section(s.anchor))::geometry('LINESTRING', $SRID) as geom from albion.section as s
-where not exists (select 1 from sorted as st where st.section_id=s.id)
-;
-
create or replace function albion.to_section(geom geometry, anchor geometry, z_scale real)
returns geometry
language plpython3u immutable
@@ -667,112 +633,22 @@ $$
$$
;
-create materialized view albion.radiometry_section as
-select r.id as radiometry_id, s.id as section_id,
- (albion.to_section(r.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.radiometry as r
-join _albion.hole as h on h.id=r.hole_id, _albion.section as s
-;
-
-create index radiometry_section_geom_idx on albion.radiometry_section using gist(geom)
-;
-
-create index radiometry_section_radiometry_id_idx on albion.radiometry_section(radiometry_id)
-;
-
-create materialized view albion.resistivity_section as
-select r.id as resistivity_id, s.id as section_id,
- (albion.to_section(r.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.resistivity as r
-join _albion.hole as h on h.id=r.hole_id, _albion.section as s
-;
-
-create index resistivity_section_geom_idx on albion.resistivity_section using gist(geom)
-;
-
-create index resistivity_section_resistivity_id_idx on albion.resistivity_section(resistivity_id)
-;
-
-create view albion.current_node_section as
-select row_number() over() as id, n.id as node_id, h.collar_id, n.from_, n.to_, n.graph_id, s.id as section_id,
- (albion.to_section(n.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.node as n
-join _albion.hole as h on h.id=n.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-;
-
create view albion.hole_section as
-select row_number() over() as id, h.id as hole_id, h.collar_id, h.depth_, s.id as section_id,
+select row_number() over() as id, h.id as hole_id, h.depth_, s.id as section_id,
(albion.to_section(h.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.hole as h
-join _albion.collar as c on c.id=h.collar_id, _albion.section as s
+from _albion.section as s
+join _albion.hole as h on s.geom && h.geom and st_intersects(st_startpoint(h.geom), s.geom)
;
-create view albion.current_hole_section as
-select row_number() over() as id, h.id as hole_id, h.collar_id, h.depth_, s.id as section_id,
- (albion.to_section(h.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.hole as h
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-;
-create view albion.current_mineralization_section as
-select row_number() over() as id, m.hole_id as hole_id, h.collar_id, m.level_, m.oc, m.accu, m.grade, s.id as section_id,
- (albion.to_section(m.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.mineralization as m
-join _albion.hole as h on h.id=m.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
+create view albion.node_section as
+select row_number() over() as id, n.id as node_id, h.id as hole_id, n.from_, n.to_, n.graph_id, s.id as section_id,
+ (albion.to_section(n.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom, n.parent
+from _albion.section as s
+join _albion.hole as h on s.geom && h.geom and st_intersects(st_startpoint(h.geom), s.geom)
+join _albion.node as n on n.hole_id = h.id
;
-create view albion.current_radiometry_section as
-select row_number() over() as id, r.hole_id as hole_id, h.collar_id, r.gamma, s.id as section_id,
- rs.geom::geometry('LINESTRING', $SRID) as geom
-from _albion.radiometry as r
-join _albion.hole as h on h.id=r.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-join albion.radiometry_section as rs on rs.radiometry_id=r.id and rs.section_id=s.id
-;
-
-create view albion.current_resistivity_section as
-select row_number() over() as id, r.hole_id as hole_id, h.collar_id, r.rho, s.id as section_id,
- rs.geom::geometry('LINESTRING', $SRID) as geom
-from _albion.resistivity as r
-join _albion.hole as h on h.id=r.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-join albion.resistivity_section as rs on rs.resistivity_id=r.id and rs.section_id=s.id
-;
-
-
-create view albion.current_formation_section as
-select row_number() over() as id, r.hole_id as hole_id, h.collar_id, r.code, r.comments, s.id as section_id,
- (albion.to_section(r.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.formation as r
-join _albion.hole as h on h.id=r.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-;
-
-create view albion.current_lithology_section as
-select row_number() over() as id, r.hole_id as hole_id, h.collar_id, r.code, r.comments, s.id as section_id,
- (albion.to_section(r.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.lithology as r
-join _albion.hole as h on h.id=r.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-;
-
-create view albion.current_facies_section as
-select row_number() over() as id, r.hole_id as hole_id, h.collar_id, r.code, r.comments, s.id as section_id,
- (albion.to_section(r.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from _albion.facies as r
-join _albion.hole as h on h.id=r.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-;
create or replace function albion.section_at_group(section_id_ varchar, group_id_ integer)
returns geometry
@@ -782,13 +658,13 @@ $$
begin
return (
with hull as (
- select st_unaryunion(st_collect(c.geom)) as geom
+ select st_multi(st_unaryunion(st_collect(c.geom))) as geom
from _albion.cell as c
join _albion.group_cell as gc on gc.cell_id=c.id
where gc.section_id=section_id_ and gc.group_id <= group_id_
),
hull_contour as (
- select st_exteriorring(geom) as geom from hull
+ select st_exteriorring(geom) as geom from (select (st_dump(geom)).geom from hull) as t
),
seg as (
select ST_PointN(geom, generate_series(1, ST_NPoints(geom)-1)) as sp, ST_PointN(geom, generate_series(2, ST_NPoints(geom) )) as ep
@@ -925,61 +801,14 @@ $$
ito_ -= OC+IC-1
if ifrom_ >= 0 and ito_ > 0 and c:
accu = numpy.sum(AVP[ifrom_:ito_])
- grade = accu/(ito_ - ifrom_)
oc = (ito_ - ifrom_)*measure_thickness
+ grade = accu/oc
result.append((cut, ifrom_*measure_thickness + first_from_, ito_*measure_thickness + first_from_, oc, accu, grade))
return result
$$
;
-select hole_id, (t.r).level_, (t.r).from_, (t.r).to_, (t.r).oc, (t.r).accu, (t.r).grade
-from (
-select hole_id, albion.segmentation(
- array_agg(gamma order by from_),array_agg(from_ order by from_), array_agg(to_ order by from_),
- 1., 1., 10) as r
-from _albion.radiometry
-group by hole_id
-) as t
-;
-
-create table albion.test_mineralization(
- id varchar primary key default _albion.unique_id()::varchar,
- hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
- level_ real,
- from_ real,
- to_ real,
- oc real,
- accu real,
- grade real,
- comments varchar,
- geom geometry('LINESTRINGZ', $SRID))
-;
-
-insert into albion.test_mineralization(hole_id, level_, from_, to_, oc, accu, grade)
-select hole_id, (t.r).level_, (t.r).from_, (t.r).to_, (t.r).oc, (t.r).accu, (t.r).grade
-from (
-select hole_id, albion.segmentation(
- array_agg(gamma order by from_),array_agg(from_ order by from_), array_agg(to_ order by from_),
- 1., 1., 10) as r
-from _albion.radiometry
-group by hole_id
-) as t
-;
-
-update albion.test_mineralization set geom=albion.hole_piece(from_, to_, hole_id)
-;
-
-create view albion.current_test_mineralization_section as
-select row_number() over() as id, m.hole_id, h.collar_id, m.level_, m.oc, m.accu, m.grade, s.id as section_id,
- (albion.to_section(m.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
-from albion.test_mineralization as m
-join _albion.hole as h on h.id=m.hole_id
-join _albion.collar as c on c.id=h.collar_id
-join _albion.section as s on st_intersects(s.geom, c.geom)
-;
-
-
create materialized view albion.all_edge as
select case when a < b then a else b end as start_, case when a < b then b else a end as end_
from _albion.cell
@@ -991,54 +820,64 @@ select case when c < a then c else a end as start_, case when c < a then a else
from _albion.cell
;
-create view albion.possible_edge as
+create or replace view albion.possible_edge as
with tan_ang as (
select tan(correlation_angle*pi()/180) as value, tan(parent_correlation_angle*pi()/180) as parent_value
-
from _albion.metadata
),
result as (
-select ns.id as start_, ne.id as end_, ns.graph_id as graph_id, (st_makeline(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5)))::geometry('LINESTRINGZ', $SRID) as geom, null as parent
+select ns.id as start_, ne.id as end_, ns.graph_id as graph_id, (st_makeline(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5)))::geometry('LINESTRINGZ', $SRID) as geom --, null as parent
+
from albion.all_edge as e
-join _albion.hole as hs on hs.collar_id=e.start_
-join _albion.hole as he on he.collar_id=e.end_
+join _albion.hole as hs on hs.id=e.start_
+join _albion.hole as he on he.id=e.end_
join _albion.node as ns on ns.hole_id=hs.id
join _albion.node as ne on ne.hole_id=he.id, tan_ang
where ns.graph_id = ne.graph_id
-and abs(st_z(st_3dlineinterpolatepoint(ns.geom, .5))-st_z(st_3dlineinterpolatepoint(ne.geom,.5)))
- /st_distance(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5)) < tan_ang.value
+and (
+ (
+ abs(ns.from_-ns.to_) >= abs(ne.from_-ne.to_)
+ and st_z(st_startpoint(ns.geom)) + st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.value >= st_z(st_startpoint(ne.geom))
+ and st_z(st_endpoint(ns.geom)) - st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.value <= st_z(st_endpoint(ne.geom))
+ )
+ or
+ (
+ abs(ns.from_-ns.to_) < abs(ne.from_-ne.to_)
+ and st_z(st_startpoint(ne.geom)) + st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.value >= st_z(st_startpoint(ns.geom))
+ and st_z(st_endpoint(ne.geom)) - st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.value <= st_z(st_endpoint(ns.geom))
+ )
+ )
+
and st_distance( ne.geom, ns.geom ) < ( select correlation_distance from albion.metadata )
and ns.parent is null
and ne.parent is null
-union all
+union all -- for graphs with parents
-select ns.id as start_, ne.id as end_, ns.graph_id as graph_id, (st_makeline(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5)))::geometry('LINESTRINGZ', $SRID) as geom, ns.parent as parent
+select ns.id as start_, ne.id as end_, ns.graph_id as graph_id, (st_makeline(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5)))::geometry('LINESTRINGZ', $SRID) as geom --, ns.parent as parent
from _albion.edge as pe
join _albion.node as pns on pns.id=pe.start_
join _albion.node as pne on pne.id=pe.end_
join _albion.node as ns on ns.parent=pns.id
join _albion.node as ne on ne.parent=pne.id, tan_ang
where ns.graph_id = ne.graph_id
-and abs( -- tan(A-B) = (tan(A)-tan(B))/(1+tan(A)tan(B)
+and
+ (
(
- (st_z(st_3dlineinterpolatepoint(ns.geom, .5))-st_z(st_3dlineinterpolatepoint(ne.geom,.5)))
- /st_distance(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5))
- -
- (st_z(st_3dlineinterpolatepoint(pns.geom, .5))-st_z(st_3dlineinterpolatepoint(pne.geom,.5)))
- /st_distance(st_3dlineinterpolatepoint(pns.geom, .5), st_3dlineinterpolatepoint(pne.geom, .5))
+ abs(ns.from_-ns.to_) >= abs(ne.from_-ne.to_)
+ and st_z(st_startpoint(ns.geom)) + st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.parent_value + (st_z(st_3dlineinterpolatepoint(pne.geom, .5)) - st_z(st_3dlineinterpolatepoint(pns.geom, .5))) >= st_z(st_startpoint(ne.geom))
+ and st_z(st_endpoint(ns.geom)) - st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.parent_value + (st_z(st_3dlineinterpolatepoint(pne.geom, .5)) - st_z(st_3dlineinterpolatepoint(pns.geom, .5))) <= st_z(st_endpoint(ne.geom))
+
)
- /
+ or
(
- 1.0
- +
- (st_z(st_3dlineinterpolatepoint(ns.geom, .5))-st_z(st_3dlineinterpolatepoint(ne.geom,.5)))
- /st_distance(st_3dlineinterpolatepoint(ns.geom, .5), st_3dlineinterpolatepoint(ne.geom, .5))
- *
- (st_z(st_3dlineinterpolatepoint(pns.geom, .5))-st_z(st_3dlineinterpolatepoint(pne.geom,.5)))
- /st_distance(st_3dlineinterpolatepoint(pns.geom, .5), st_3dlineinterpolatepoint(pne.geom, .5))
+ abs(ns.from_-ns.to_) < abs(ne.from_-ne.to_)
+ and st_z(st_startpoint(ne.geom)) + st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.parent_value + (st_z(st_3dlineinterpolatepoint(pns.geom, .5)) - st_z(st_3dlineinterpolatepoint(pne.geom, .5))) >= st_z(st_startpoint(ns.geom))
+
+ and st_z(st_endpoint(ne.geom)) - st_distance(st_startpoint(ns.geom), st_startpoint(ne.geom))*tan_ang.parent_value + (st_z(st_3dlineinterpolatepoint(pns.geom, .5)) - st_z(st_3dlineinterpolatepoint(pne.geom, .5)) ) <= st_z(st_endpoint(ns.geom))
+
+ )
)
- ) < tan_ang.parent_value
)
select row_number() over() as id, * from result
;
@@ -1065,11 +904,11 @@ $$
if new.start_ > new.end_ then
select new.start_, new.end_ into new.end_, new.start_;
end if;
- -- @todo check that edge is in all_edge
+ -- check that edge is in all_edge
select count(1)
from albion.all_edge as ae
- join _albion.hole as hs on hs.collar_id=ae.start_
- join _albion.hole as he on he.collar_id=ae.end_
+ join _albion.hole as hs on hs.id=ae.start_
+ join _albion.hole as he on he.id=ae.end_
join _albion.node as ns on (ns.hole_id in (hs.id, he.id) and ns.id=new.start_)
join _albion.node as ne on (ne.hole_id in (hs.id, he.id) and ne.id=new.end_)
into edge_ok;
@@ -1103,11 +942,11 @@ create trigger edge_instead_trig
for each row execute procedure albion.edge_instead_fct()
;
-create view albion.current_edge_section as
-with collar_idx as (
- select c.id, rank() over(partition by s.id order by st_linelocatepoint(s.geom, c.geom)) as rk, c.geom, s.id as section_id
+create view albion.edge_section as
+with hole_idx as (
+ select h.id, rank() over(partition by s.id order by st_linelocatepoint(s.anchor, st_startpoint(h.geom))) as rk, s.id as section_id
from _albion.section as s
- join _albion.collar as c on st_intersects(s.geom, c.geom) and st_intersects(s.geom, c.geom)
+ join _albion.hole as h on s.geom && h.geom and st_intersects(s.geom, st_startpoint(h.geom))
)
select s.id || ' ' || e.id as id, e.id as edge_id, e.start_, e.end_, e.graph_id, s.id as section_id,
(albion.to_section(e.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
@@ -1116,15 +955,17 @@ join _albion.node as ns on ns.id=e.start_
join _albion.node as ne on ne.id=e.end_
join _albion.hole as hs on hs.id=ns.hole_id
join _albion.hole as he on he.id=ne.hole_id
-join collar_idx as cs on cs.id=hs.collar_id
-join collar_idx as ce on ce.id=he.collar_id,
+join hole_idx as cs on cs.id=hs.id
+join hole_idx as ce on ce.id=he.id,
_albion.section as s
where ((cs.rk = ce.rk + 1) or (ce.rk = cs.rk + 1))
and cs.section_id=s.id
and ce.section_id=s.id
;
-create or replace function albion.current_edge_section_instead_fct()
+alter view albion.edge_section alter column id set default _albion.unique_id();
+
+create or replace function albion.edge_section_instead_fct()
returns trigger
language plpgsql
as
@@ -1133,13 +974,13 @@ $$
new_geom geometry;
begin
if tg_op in ('INSERT', 'UPDATE') then
- new.start_ := coalesce(new.start_, (select node_id from albion.current_node_section as n, _albion.metadata as m
+ new.start_ := coalesce(new.start_, (select node_id from albion.node_section as n, _albion.metadata as m
where st_dwithin(n.geom, st_startpoint(new.geom), m.snap_distance)
and graph_id=new.graph_id
order by st_distance(n.geom, st_startpoint(new.geom)) asc
limit 1
));
- new.end_ := coalesce(new.end_, (select node_id from albion.current_node_section as n, _albion.metadata as m
+ new.end_ := coalesce(new.end_, (select node_id from albion.node_section as n, _albion.metadata as m
where st_dwithin(n.geom, st_endpoint(new.geom), m.snap_distance)
and graph_id=new.graph_id
order by st_distance(n.geom, st_endpoint(new.geom)) asc
@@ -1152,6 +993,16 @@ $$
select st_makeline(st_3dlineinterpolatepoint(s.geom, .5), st_3dlineinterpolatepoint(e.geom, .5))
from _albion.node as s, _albion.node as e
where s.id=new.start_ and e.id=new.end_ into new_geom;
+
+ -- test if edge is possible
+ if not exists (select 1
+ from albion.all_edge as ae
+ join _albion.node as ns on ae.start_ = ns.hole_id
+ join _albion.node as ne on ae.end_ = ne.hole_id
+ where ns.id = new.start_ and ne.id = new.end_) then
+ raise 'impossible edge';
+ end if;
+
end if;
if tg_op = 'INSERT' then
@@ -1171,27 +1022,32 @@ $$
$$
;
-create trigger current_edge_section_instead_trig
- instead of insert or update or delete on albion.current_edge_section
- for each row execute procedure albion.current_edge_section_instead_fct()
+create trigger edge_section_instead_trig
+ instead of insert or update or delete on albion.edge_section
+ for each row execute procedure albion.edge_section_instead_fct()
;
-create view albion.current_possible_edge_section as
+create view albion.possible_edge_section as
select row_number() over() as id, e.start_, e.end_, e.graph_id, s.id as section_id,
- (albion.to_section(e.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom, e.parent
+ (albion.to_section(e.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom --, e.parent
from albion.possible_edge as e
join _albion.node as ns on ns.id=e.start_
join _albion.node as ne on ne.id=e.end_
join _albion.hole as hs on hs.id=ns.hole_id
join _albion.hole as he on he.id=ne.hole_id
-join _albion.collar as cs on cs.id=hs.collar_id
-join _albion.collar as ce on ce.id=he.collar_id
-join _albion.section as s on st_intersects(s.geom, cs.geom) and st_intersects(s.geom, ce.geom)
+join _albion.section as s on s.geom && hs.geom and st_intersects(s.geom, st_startpoint(hs.geom)) and
+ s.geom && he.geom and st_intersects(s.geom, st_startpoint(he.geom))
;
+create type albion.volume_row as (
+ geom geometry('MULTIPOLYGONZ', $SRID),
+ face1 geometry('MULTIPOLYGONZ', $SRID),
+ face2 geometry('MULTIPOLYGONZ', $SRID),
+ face3 geometry('MULTIPOLYGONZ', $SRID))
+;
-create or replace function albion.elementary_volumes(cell_id_ varchar, graph_id_ varchar, geom_ geometry, holes_ varchar[], starts_ varchar[], ends_ varchar[], hole_ids_ varchar[], node_ids_ varchar[], nodes_ geometry[], end_ids_ varchar[], end_geoms_ geometry[])
-returns setof geometry
+create or replace function albion.elementary_volumes(cell_id_ varchar, graph_id_ varchar, geom_ geometry, holes_ varchar[], starts_ varchar[], ends_ varchar[], hole_ids_ varchar[], node_ids_ varchar[], nodes_ geometry[], end_ids_ varchar[], end_geoms_ geometry[], end_holes_ varchar[], end_node_relative_distance real, end_node_relative_thickness real)
+returns setof albion.volume_row
language plpython3u immutable
as
$$
@@ -1206,17 +1062,37 @@ $$
# ' '.join(node_ids_)+'\n'+
# ' '.join(nodes_)+'\n'+
# ' '.join(end_ids_)+'\n'+
-# ' '.join(end_geoms_)+'\n'
+# ' '.join(end_geoms_)+'\n'+
+# ' '.join(end_holes_)+'\n'
#)
$INCLUDE_ELEMENTARY_VOLUME
-for v in elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end_ids_, end_geoms_, $SRID):
- yield v
+for g, f1, f2, f3 in elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end_ids_, end_geoms_, end_holes_, $SRID, end_node_relative_distance, end_node_relative_thickness):
+ yield g, f1, f2, f3
$$
;
-create or replace view albion.volume as
-select id, graph_id, cell_id, triangulation
-from _albion.volume
+create or replace function albion.volume_of_geom(multipoly geometry)
+returns real
+language plpython3u immutable
+as
+$$
+ from shapely import wkb
+ import plpy
+ from numpy import array, average
+
+ m = wkb.loads(bytes.fromhex(multipoly))
+ volume = 0
+ for p in m:
+ r = p.exterior.coords
+ v210 = r[2][0]*r[1][1]*r[0][2];
+ v120 = r[1][0]*r[2][1]*r[0][2];
+ v201 = r[2][0]*r[0][1]*r[1][2];
+ v021 = r[0][0]*r[2][1]*r[1][2];
+ v102 = r[1][0]*r[0][1]*r[2][2];
+ v012 = r[0][0]*r[1][1]*r[2][2];
+ volume += (1./6.)*(-v210 + v120 + v201 - v021 - v102 + v012)
+ return volume
+$$
;
create or replace function albion.is_closed_volume(multipoly geometry)
@@ -1239,6 +1115,11 @@ $$
$$
;
+create or replace view albion.volume as
+select id, graph_id, cell_id, triangulation, albion.volume_of_geom(triangulation) as volume--, albion.is_closed_volume(triangulation) as is_closed
+from _albion.volume
+;
+
create or replace function albion.mesh_boundarie(multipoly geometry)
returns geometry
language plpython3u immutable
@@ -1264,30 +1145,6 @@ $$
$$
;
-create or replace function albion.volume_of_geom(multipoly geometry)
-returns real
-language plpython3u immutable
-as
-$$
- from shapely import wkb
- import plpy
- from numpy import array, average
-
- m = wkb.loads(bytes.fromhex(multipoly))
- volume = 0
- for p in m:
- r = p.exterior.coords
- v210 = r[2][0]*r[1][1]*r[0][2];
- v120 = r[1][0]*r[2][1]*r[0][2];
- v201 = r[2][0]*r[0][1]*r[1][2];
- v021 = r[0][0]*r[2][1]*r[1][2];
- v102 = r[1][0]*r[0][1]*r[2][2];
- v012 = r[0][0]*r[1][1]*r[2][2];
- volume += (1./6.)*(-v210 + v120 + v201 - v021 - v102 + v012)
- return volume
-$$
-;
-
create or replace function albion.volume_union(multipoly geometry)
returns geometry
@@ -1434,18 +1291,18 @@ $$
;
create view albion.end_node as
-select id, geom, node_id, collar_id, graph_id
+select id, geom, node_id, hole_id, graph_id
from _albion.end_node
;
-- view of termination edges
create or replace view albion.half_edge as
-select n.id as node_id, n.graph_id, h.collar_id, case when ae.start_=h.collar_id then ae.end_ else ae.start_ end as other
+select n.id as node_id, n.graph_id, h.id as hole_id, case when ae.start_=h.id then ae.end_ else ae.start_ end as other
from _albion.node as n
join _albion.hole as h on h.id=n.hole_id
-join albion.all_edge as ae on (ae.start_=h.collar_id or ae.end_=h.collar_id)
+join albion.all_edge as ae on (ae.start_=h.id or ae.end_=h.id)
except
-select n.id, n.graph_id, h.collar_id, case when e.start_=n.id then he.collar_id else hs.collar_id end as other
+select n.id, n.graph_id, h.id as hole_id, case when e.start_=n.id then he.id else hs.id end as other
from _albion.node as n
join _albion.hole as h on h.id=n.hole_id
join _albion.edge as e on (e.start_=n.id or e.end_=n.id)
@@ -1455,50 +1312,74 @@ join _albion.hole as hs on hs.id=ns.hole_id
join _albion.hole as he on he.id=ne.hole_id
;
-create function albion.end_node_geom(node_geom_ geometry, collar_geom_ geometry)
+create or replace function albion.end_node_geom(node_geom_ geometry, collar_geom_ geometry, rel_distance real default .3, rel_thickness real default .3, nx real default null, ny real default null, nz real default null)
returns geometry
language plpython3u
as
$$
from numpy import array
+ from numpy import cross
from shapely import wkb
from shapely.geometry import LineString
from shapely import geos
+ from math import sqrt
geos.WKBWriter.defaults['include_srid'] = True
- REL_DISTANCE = .3
- HEIGHT = 1.
-
node_geom = wkb.loads(bytes.fromhex(node_geom_))
collar_geom = wkb.loads(bytes.fromhex(collar_geom_))
node_coords = array(node_geom.coords)
+ thickness = rel_thickness*abs(node_coords[0][2] - node_coords[1][2])
center = .5*(node_coords[0] + node_coords[1])
dir = array(collar_geom.coords[0]) - center
dir[2] = 0
- dir *= REL_DISTANCE
- top = center + dir + array([0,0,.5*HEIGHT])
- bottom = center + dir - array([0,0,.5*HEIGHT])
+ dir *= rel_distance
+ dir = cross(array([nx, ny, nz]), cross(dir, array([0,0,1])))
+ top = center + dir + array([0,0,.5*thickness])
+ bottom = center + dir - array([0,0,.5*thickness])
result = LineString([tuple(top), tuple(bottom)])
+
geos.lgeos.GEOSSetSRID(result._geom, geos.lgeos.GEOSGetSRID(node_geom._geom))
return result.wkb_hex
$$
;
-create view albion.dynamic_end_node as
-select row_number() over() as id, he.graph_id, n.id as node_id, albion.end_node_geom(n.geom, c.geom)::geometry('LINESTRINGZ', $SRID) as geom, c.id as collar_id
+create or replace view albion.normal as
+select e.id, e.start_, e.end_,
+ - (st_x(st_endpoint(geom)) - st_x(st_startpoint(geom))) * ((st_z(st_endpoint(geom)) - st_z(st_startpoint(geom)))) as nx,
+ - (st_y(st_endpoint(geom)) - st_y(st_startpoint(geom))) * ((st_z(st_endpoint(geom)) - st_z(st_startpoint(geom)))) as ny,
+ (st_x(st_endpoint(geom)) - st_x(st_startpoint(geom)))^2 + ((st_y(st_endpoint(geom)) - st_y(st_startpoint(geom))))^2 as nz,
+ (180/pi())*atan(abs(st_z(st_endpoint(geom)) - st_z(st_startpoint(geom)))/st_length(geom)) as angl
+from _albion.edge as e
+;
+
+create or replace view albion.average_normal as
+with nrml as (
+ select avg(nx) as nx, avg(ny) as ny, avg(nz) as nz, n.id
+ from _albion.node as n
+ left join albion.normal as e on e.start_=n.id or e.end_=n.id
+ group by n.id
+)
+select id, coalesce(nx/sqrt(nx^2+ny^2+nz^2), 0) as nx, coalesce(ny/sqrt(nx^2+ny^2+nz^2), 0) as ny, coalesce(nz/sqrt(nx^2+ny^2+nz^2), 1) as nz
+from nrml
+;
+
+
+create or replace view albion.dynamic_end_node as
+select row_number() over() as id, he.graph_id, n.id as node_id, albion.end_node_geom(n.geom, st_startpoint(h.geom), m.end_node_relative_distance, m.end_node_relative_thickness, nrml.nx::real, nrml.ny::real, nrml.nz::real)::geometry('LINESTRINGZ', $SRID) as geom, h.id as hole_id
from albion.half_edge as he
join _albion.node as n on n.id=he.node_id
join _albion.hole as h on h.id=he.other
-join _albion.collar as c on c.id=h.collar_id
+join _albion.metadata as m on 't'
+join albion.average_normal as nrml on nrml.id = coalesce(n.parent, n.id);
;
-create view albion.current_end_node_section as
-with collar_idx as (
- select c.id, rank() over(partition by s.id order by st_linelocatepoint(s.geom, c.geom)) as rk, c.id as collar_id, c.geom, s.id as section_id
+create or replace view albion.end_node_section as
+with hole_idx as (
+ select h.id, rank() over(partition by s.id order by st_linelocatepoint(s.anchor, st_startpoint(h.geom))) as rk, h.id as hole_id, s.id as section_id
from _albion.section as s
- join _albion.collar as c on st_intersects(s.geom, c.geom)
+ join _albion.hole as h on s.geom && h.geom and st_intersects(s.geom, st_startpoint(h.geom))
)
select tn.id||' '||s.id as id, tn.id as end_node_id, n.id as node_id, tn.graph_id, s.id as section_id,
(albion.to_section(tn.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom,
@@ -1507,12 +1388,12 @@ from _albion.end_node as tn
join _albion.node as n on n.id=tn.node_id
join _albion.hole as h on h.id=n.hole_id
join _albion.section as s on true
-join collar_idx as cn on (cn.collar_id=h.collar_id and cn.section_id=s.id)
-join collar_idx as cc on (cc.collar_id=tn.collar_id and cc.section_id=s.id)
+join hole_idx as cn on (cn.id=h.id and cn.section_id=s.id)
+join hole_idx as cc on (cc.id=tn.hole_id and cc.section_id=s.id)
where cn.rk=cc.rk+1 or cc.rk=cn.rk+1
;
-create or replace function albion.current_end_node_section_instead_fct()
+create or replace function albion.end_node_section_instead_fct()
returns trigger
language plpgsql
as
@@ -1541,33 +1422,31 @@ $$
$$
;
-create trigger current_end_node_section_instead_trig
- instead of insert or update or delete on albion.current_end_node_section
- for each row execute procedure albion.current_end_node_section_instead_fct()
+create trigger end_node_section_instead_trig
+ instead of insert or update or delete on albion.end_node_section
+ for each row execute procedure albion.end_node_section_instead_fct()
;
-create or replace view albion.current_section_polygon as
+create or replace view albion.section_polygon as
with node as (
- select node_id, section_id, geom from albion.current_node_section
+ select node_id, section_id, geom from albion.node_section
),
edge as (
- select graph_id, section_id, start_, end_ from albion.current_edge_section
+ select graph_id, section_id, start_, end_ from albion.edge_section
),
poly as (
- select st_union(
+ select
('SRID=$SRID; POLYGON(('||
st_x(st_startpoint(ns.geom)) ||' '||st_y(st_startpoint(ns.geom))||','||
st_x(st_endpoint(ns.geom)) ||' '||st_y(st_endpoint(ns.geom)) ||','||
st_x(st_endpoint(ne.geom)) ||' '||st_y(st_endpoint(ne.geom)) ||','||
st_x(st_startpoint(ne.geom)) ||' '||st_y(st_startpoint(ne.geom))||','||
st_x(st_startpoint(ns.geom)) ||' '||st_y(st_startpoint(ns.geom))||
- '))')::geometry
- ) as geom, e.graph_id, e.section_id
+ '))')::geometry as geom, e.graph_id, e.section_id
from edge as e
join node as ns on ns.node_id=e.start_ and ns.section_id=e.section_id
join node as ne on ne.node_id=e.end_ and ne.section_id=e.section_id
- group by e.graph_id, e.section_id
),
term as (
select ('SRID=$SRID; POLYGON(('||
@@ -1578,16 +1457,17 @@ term as (
st_x(st_startpoint(t.node_geom)) ||' '||st_y(st_startpoint(t.node_geom))||
'))')::geometry as geom,
t.graph_id, t.section_id
- from albion.current_end_node_section as t
+ from albion.end_node_section as t
)
-select row_number() over() as id, geom::geometry('POLYGON', $SRID), graph_id, section_id
-from (select * from poly union all select * from term) as t
+select row_number() over() as id, st_multi(st_union(geom))::geometry('MULTIPOLYGON', $SRID) as geom, graph_id, section_id
+from (select * from poly union all select * from term where st_isvalid(geom)) as t
+group by graph_id, section_id
;
-create or replace view albion.current_section_intersection as
+create or replace view albion.section_intersection as
with inter as (
select st_collectionextract((st_dump(st_intersection(a.geom, b.geom))).geom, 3) as geom
- from albion.current_section_polygon as a, albion.current_section_polygon as b
+ from albion.section_polygon as a, albion.section_polygon as b
where a.id>b.id
and a.graph_id=b.graph_id
and a.section_id=b.section_id
@@ -1604,12 +1484,12 @@ where not st_isempty(geom)
create or replace view albion.dynamic_volume as
with res as (
select
-c.id as cell_id, g.id as graph_id, ed.starts, ed.ends, nd.hole_ids as hole_ids, nd.ids as node_ids, nd.geoms as node_geoms, en.ids as end_ids, en.geoms as end_geoms, c.geom, ARRAY[ha.id, hb.id, hc.id] as holes
+c.id as cell_id, g.id as graph_id, ed.starts, ed.ends, nd.hole_ids as hole_ids, nd.ids as node_ids, nd.geoms as node_geoms, en.ids as end_ids, en.geoms as end_geoms, c.geom, ARRAY[ha.id, hb.id, hc.id] as holes, en.end_holes
from _albion.graph as g
join _albion.cell as c on true
-join _albion.hole as ha on ha.collar_id = c.a
-join _albion.hole as hb on hb.collar_id = c.b
-join _albion.hole as hc on hc.collar_id = c.c
+join _albion.hole as ha on ha.id = c.a
+join _albion.hole as hb on hb.id = c.b
+join _albion.hole as hc on hc.id = c.c
join lateral (
select coalesce(array_agg(n.id), '{}'::varchar[]) as ids, coalesce(array_agg(n.hole_id), '{}'::varchar[]) as hole_ids, coalesce(array_agg(n.geom), '{}'::geometry[]) as geoms
from _albion.node as n
@@ -1625,16 +1505,22 @@ join lateral (
and e.graph_id=g.id
) as ed on true
join lateral (
- select coalesce(array_agg(en.node_id), '{}'::varchar[]) as ids, coalesce(array_agg(en.geom), '{}'::geometry[]) as geoms
+ select coalesce(array_agg(en.node_id), '{}'::varchar[]) as ids, coalesce(array_agg(en.geom), '{}'::geometry[]) as geoms, coalesce(array_agg(en.hole_id), '{}'::varchar[]) as end_holes
from _albion.end_node as en
join _albion.node as n on n.id=en.node_id
- where en.collar_id in (c.a, c.b, c.c)
+ where en.hole_id in (c.a, c.b, c.c)
and n.hole_id in (ha.id, hb.id, hc.id)
and en.graph_id=g.id
) as en on true
)
-select cell_id, graph_id, albion.elementary_volumes(cell_id, graph_id, st_force3d(geom), holes, starts, ends, hole_ids, node_ids, node_geoms, end_ids, end_geoms)::geometry('MULTIPOLYGONZ', $SRID) as geom, starts, ends, holes, hole_ids, node_ids, end_ids, end_geoms
-from res
+select cell_id, graph_id,
+ t.geom::geometry('MULTIPOLYGONZ', $SRID),
+ t.face1::geometry('MULTIPOLYGONZ', $SRID),
+ t.face2::geometry('MULTIPOLYGONZ', $SRID),
+ t.face3::geometry('MULTIPOLYGONZ', $SRID),
+ starts, ends, holes, hole_ids, node_ids, end_ids, end_geoms
+from res, albion.metadata m
+join lateral albion.elementary_volumes(cell_id, graph_id, st_force3d(geom), holes, starts, ends, hole_ids, node_ids, node_geoms, end_ids, end_geoms, end_holes, m.end_node_relative_distance, m.end_node_relative_thickness) as t on true
;
@@ -1679,3 +1565,219 @@ from res
--'01050000A0787F00000E00000001020000800200000013154A5788BC1341F27E88ADD2A93F41DDC836A48ECB7640F78772A388BC13411BFEBE9FD2A93F41C0A2699C9393764001020000800200000059D97C6C85BC13418A67D48DBAA93F41FF7B08EA919F7640418F5F6685BC1341B0A9D78CBAA93F4178920C2DC58A764001020000800200000013154A5788BC1341F27E88ADD2A93F41DDC836A48ECB7640F78772A388BC13411BFEBE9FD2A93F41C0A2699C939376400102000080020000005E3F399385BC13419833B790BAA93F412744AD66C4EA764050BFC17285BC1341BB98A18EBAA93F4131BD49D291AF764001020000800200000013154A5788BC1341F27E88ADD2A93F41DDC836A48ECB7640F78772A388BC13411BFEBE9FD2A93F41C0A2699C93937640010200008002000000EAF7DBB529BC1341350EF10DD4A93F415EECEAE169E176400A74A55E2ABC1341E896ED28D4A93F4169719E7FAD947640010200008002000000EAF7DBB529BC1341350EF10DD4A93F415EECEAE169E176400A74A55E2ABC1341E896ED28D4A93F4169719E7FAD94764001020000800200000059D97C6C85BC13418A67D48DBAA93F41FF7B08EA919F7640418F5F6685BC1341B0A9D78CBAA93F4178920C2DC58A7640010200008002000000EAF7DBB529BC1341350EF10DD4A93F415EECEAE169E176400A74A55E2ABC1341E896ED28D4A93F4169719E7FAD9476400102000080020000005E3F399385BC13419833B790BAA93F412744AD66C4EA764050BFC17285BC1341BB98A18EBAA93F4131BD49D291AF764001020000800200000056B7652688BC1341EA1D85B9D2A93F41D7DF7D1858F87640E1BD403F88BC13418DABDEB2D2A93F41BFCC2B28C0DE76400102000080020000005E3F399385BC13419833B790BAA93F412744AD66C4EA764050BFC17285BC1341BB98A18EBAA93F4131BD49D291AF764001020000800200000056B7652688BC1341EA1D85B9D2A93F41D7DF7D1858F87640E1BD403F88BC13418DABDEB2D2A93F41BFCC2B28C0DE764001020000800200000042B5BD4C29BC134102FDA4FBD3A93F4171017AF02C16774018C4BC7729BC134173507003D4A93F4124AB1F80CAFF7640'::geometry))
--;
+-- collect triangles of neighbor elementary volumes
+create or replace function albion.triangle_intersection(t1_ geometry, t2_ geometry)
+returns geometry
+language plpython3u immutable
+as
+$$
+ from shapely import geos
+ from shapely.geometry import MultiPolygon, Polygon
+ from shapely import wkb
+ import numpy
+ import plpy
+ geos.WKBWriter.defaults['include_srid'] = True
+ t1 = wkb.loads(bytes.fromhex(t1_))
+ t2 = wkb.loads(bytes.fromhex(t2_))
+
+ t1s = set((tuple(t.exterior.coords[0:3]) for t in t1))
+ t2s = set((tuple(reversed(t.exterior.coords[0:3])) for t in t2))
+
+ result = MultiPolygon([ Polygon(t) for t in t1s.intersection(t2s)])
+ if not len(result):
+ return None
+ geos.lgeos.GEOSSetSRID(result._geom, geos.lgeos.GEOSGetSRID(t1._geom))
+ return result.wkb_hex
+$$
+;
+
+--create or replace function albion.triangle_intersection(t1_ geometry, t2_ geometry)
+--returns geometry
+--language plpgsql immutable
+--as
+--$$
+-- begin
+-- return (select st_collect(geom) from
+-- ( select a.geom
+-- from st_dump(t1_) a, st_dump(t2_) b
+-- where a.geom = st_reverse(b.geom)
+-- ) as t);
+--
+-- end;
+--$$
+--;
+
+
+--create or replace view albion.volume_section as
+--with touching_cell as (
+-- select c.id, st_intersection(s.geom, c.geom) as geom, v.triangulation, s.id as section_id, v.graph_id
+-- from _albion.section as s
+-- join _albion.cell as c on c.geom && s.geom
+-- and st_intersects(c.geom, s.geom)
+-- and st_length(st_intersection(s.geom, c.geom)) > 0
+-- join _albion.volume as v on v.cell_id = c.id
+--),
+--tri as (
+-- select (st_dump(albion.triangle_intersection(c1.triangulation, c2.triangulation))).geom as geom, c1.section_id, c1.graph_id
+-- from touching_cell as c1
+-- join touching_cell as c2 on c2.id > c1.id and st_length(st_intersection(c1.geom, c2.geom)) >0 and c1.section_id = c2.section_id and c1.graph_id = c2.graph_id
+--)
+--select row_number() over() as id, st_collect(geom)::geometry('MULTIPOLYGONZ', $SRID) as geom, section_id, graph_id
+--from tri
+--group by section_id, graph_id
+--;
+
+
+create or replace view albion.edge_face as
+select t.n[1] as start_, t.n[2] as end_, face1 as geom, graph_id, cell_id, 'face1' as face
+from _albion.volume v
+join _albion.cell c on c.id = v.cell_id
+join lateral (select array_agg(x order by x) as n from (values (a), (b), (c)) as v(x)) as t on true
+union all
+select t.n[2] as start_, t.n[3] as end_, face2 as geom, graph_id, cell_id, 'face2' as face
+from _albion.volume v
+join _albion.cell c on c.id = v.cell_id
+join lateral (select array_agg(x order by x) as n from (values (a), (b), (c)) as v(x)) as t on true
+union all
+select t.n[1] as start_, t.n[3] as end_, face3 as geom, graph_id, cell_id, 'face3' as face
+from _albion.volume v
+join _albion.cell c on c.id = v.cell_id
+join lateral (select array_agg(x order by x) as n from (values (a), (b), (c)) as v(x)) as t on true
+;
+
+create view albion.section_edge as
+with hole_idx as (
+ select s.id as section_id, h.id as hole_id
+ from _albion.section as s
+ join _albion.hole as h on s.geom && h.geom and st_intersects(s.geom, st_startpoint(h.geom))
+)
+select e.start_, e.end_, hs.section_id
+from albion.all_edge as e
+join hole_idx as hs on hs.hole_id = e.start_
+join hole_idx as he on he.hole_id = e.end_ and he.section_id = hs.section_id
+;
+
+create or replace view albion.volume_section as
+select se.section_id, ef.graph_id, st_collectionhomogenize(st_collect(ef.geom))::geometry('MULTIPOLYGONZ', 32632) as geom
+from albion.section_edge as se
+join albion.edge_face as ef on ef.start_ = se.start_ and ef.end_ = se.end_ and not st_isempty(ef.geom)
+group by se.section_id, ef.graph_id
+;
+
+
+create or replace view albion.named_section as
+select s.id, s.geom, s.section, rank() over (partition by section order by st_distance(s.geom, a.anchor)) as rank_, s.cut
+from _albion.named_section as s
+join _albion.section as a on s.section = a.id
+;
+
+create or replace function albion.named_section_instead_fct()
+returns trigger
+language plpgsql
+as
+$$
+ begin
+ if tg_op in ('INSERT', 'UPDATE') then
+ new.id := coalesce(new.id, _albion.unique_id()::varchar);
+ new.cut := coalesce(new.cut, (
+ with geom as (
+ select st_dumppoints(new.geom) as pt
+ ),
+ segment as (
+ select st_makeline(lag((pt).geom) over (order by (pt).path), (pt).geom) as geom from geom
+ ),
+ filtered as (
+ select geom from segment as s
+ except
+ select s.geom from segment as s
+ join _albion.named_section as o
+ on st_intersects(o.cut, s.geom)
+ and st_linelocatepoint(s.geom, st_intersection(o.cut, s.geom)) not in (0.0, 1.0)
+ and st_geometrytype(st_intersection(o.cut, s.geom)) = 'ST_Point'
+ )
+ select st_multi(st_linemerge(st_collect(geom))) from filtered
+ ));
+ end if;
+
+
+ if tg_op = 'INSERT' then
+ insert into _albion.named_section(id, geom, cut, section)
+ values(new.id, new.geom, new.cut, new.section)
+ returning id into new.id;
+ return new;
+ elsif tg_op = 'UPDATE' then
+ update _albion.named_section set id=new.id, geom=new.geom, cut=new.cut, section=new.section
+ where id=old.id;
+ return new;
+ elsif tg_op = 'DELETE' then
+ delete from _albion.named_section where id=old.id;
+ return old;
+ end if;
+ end;
+$$
+;
+
+create trigger named_section_instead_trig
+ instead of insert or update or delete on albion.named_section
+ for each row execute procedure albion.named_section_instead_fct()
+;
+
+
+create or replace function albion.next_section(section_ varchar)
+returns geometry
+language plpgsql stable
+as
+$$
+ begin
+ return (
+ select n.cut
+ from albion.named_section as n
+ join albion.section as s on s.id=n.section
+ where s.id=section_ and st_distance(n.cut, s.anchor) > coalesce(st_distance(s.geom, s.anchor), 0)
+ order by st_distance(n.cut, s.anchor) asc
+ limit 1
+ );
+ end;
+$$
+;
+
+create or replace function albion.previous_section(section_ varchar)
+returns geometry
+language plpgsql stable
+as
+$$
+ begin
+ return (
+ select n.cut
+ from albion.named_section as n
+ join albion.section as s on s.id=n.section
+ where s.id=section_ and st_distance(n.cut, s.anchor) < coalesce(st_distance(s.geom, s.anchor), 9999999)
+ order by st_distance(n.cut, s.anchor) desc
+ limit 1
+ );
+ end;
+$$
+;
+
+
+-- TODO
+-- [x] ajout de collar stérile (avec note)
+-- [x] polygone de maillage convex hull ou un trou
+-- supprimer des cellules et les edges associés
+
+-- Methode
+-- import des collar et deviations dans répertoire + option data to_ from_
+-- calcul des minéralisations
+-- ajout de collar stériles flmaggés (verticaux)
+-- creation des sections nommées
+-- triangulation
+-- effacer des cellules
+-- creation de graph
+
+
+
+/*
+select (st_dumppoints(st_intersection(a.geom, b.geom))).geom as geom from albion.named_section as a join albion.named_section as b on st_intersects(a.geom, b.geom) and a.id > b.id
+except
+select st_force2d(geom) as geom from albion.collar
+*/
diff --git a/albion_table.sql b/albion_table.sql
new file mode 100644
index 0000000..4d40d89
--- /dev/null
+++ b/albion_table.sql
@@ -0,0 +1,62 @@
+create view albion.${NAME} as
+select t.id, t.hole_id, t.from_, t.to_, st_startpoint(h.geom)::geometry('POINTZ', ${SRID}) as geom, ${T_FIELDS}
+from _albion.${NAME} as t
+join _albion.hole as h on h.id = t.hole_id
+;
+
+alter view albion.${NAME} alter column id set default _albion.unique_id()
+;
+
+create or replace function albion.${NAME}_instead_fct()
+returns trigger
+language plpgsql
+as
+$$$$
+ begin
+ if tg_op = 'INSERT' then
+ insert into _albion.${NAME}(id, hole_id, from_, to_, ${FIELDS})
+ values(new.id, new.hole_id, new.from_, new.to_, ${NEW_FIELDS})
+ returning id into new.id;
+ return new;
+ elsif tg_op = 'UPDATE' then
+ update _albion.${NAME} set id=new.id, hole_id=new.hole_id, from_=new.from_, to_=new.to_, ${SET_FIELDS}
+ where id=old.id;
+ return new;
+ elsif tg_op = 'DELETE' then
+ delete from _albion.${NAME} where id=old.id;
+ return old;
+ end if;
+ end;
+$$$$
+;
+
+create trigger ${NAME}_instead_trig
+ instead of insert or update or delete on albion.${NAME}
+ for each row execute procedure albion.${NAME}_instead_fct()
+;
+
+create materialized view albion.${NAME}_section_geom_cache as
+select s.id as section_id, h.id as hole_id, t.id as ${NAME}_id,
+ (albion.to_section(
+ st_makeline(st_3dlineinterpolatepoint(h.geom, least(t.from_/h.depth_, 1)),
+ st_3dlineinterpolatepoint(h.geom, least(t.to_/h.depth_, 1)))
+ , s.anchor, s.scale)) as geom,
+ st_startpoint(h.geom) as collar
+from _albion.section as s, _albion.${NAME} as t
+join _albion.hole as h on h.id=t.hole_id
+;
+
+create index ${NAME}_section_geom_cache_${NAME}_id_idx on albion.${NAME}_section_geom_cache(${NAME}_id)
+;
+
+create index ${NAME}_section_geom_cache_colar_idx on albion.${NAME}_section_geom_cache using gist(collar)
+;
+
+
+create view albion.${NAME}_section as
+select row_number() over() as id, t.id as ${NAME}_id, sc.section_id, t.hole_id, sc.geom::geometry('LINESTRING', ${SRID}), ${T_FIELDS}
+from _albion.${NAME} as t
+join albion.${NAME}_section_geom_cache as sc on sc.${NAME}_id = t.id
+join _albion.section as s on st_intersects(s.geom, sc.collar) and sc.section_id = s.id
+;
+
diff --git a/axis_layer.py b/axis_layer.py
deleted file mode 100644
index af09dc5..0000000
--- a/axis_layer.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# coding: utf-8
-from qgis.core import (QgsPluginLayerType,
- QgsPluginLayer,
- QgsRectangle)
-
-from PyQt4.QtCore import pyqtSignal
-
-import traceback
-import logging
-
-
-class AxisLayerType(QgsPluginLayerType):
- def __init__(self):
- QgsPluginLayerType.__init__(self, AxisLayer.LAYER_TYPE)
-
- def createLayer(self):
- return AxisLayer()
- return True
-
- def showLayerProperties(self, layer):
- return False
-
-
-class AxisLayer(QgsPluginLayer):
-
- LAYER_TYPE = 'axis'
-
- __msg = pyqtSignal(str)
- __drawException = pyqtSignal(str)
-
- def __init__(self, crs):
- QgsPluginLayer.__init__(
- self,
- AxisLayer.LAYER_TYPE,
- 'axis plugin layer')
- self.__msg.connect(self.__print)
- self.__drawException.connect(self.__raise)
- self.setCrs(crs)
- self.setValid(True)
-
- def extent(self):
- return QgsRectangle(-1, -1, 1, 1)
-
- def __print(self, msg):
- logging.info(msg)
-
- def __raise(self, err):
- logging.error(err)
- raise Exception(err)
-
- def draw(self, rendererContext):
- try:
- painter = rendererContext.painter()
- ext = rendererContext.extent()
- map_unit_per_pixel = rendererContext.mapToPixel().\
- mapUnitsPerPixel()
- width, height = \
- int((ext.xMaximum()-ext.xMinimum())/map_unit_per_pixel),\
- int((ext.yMaximum()-ext.yMinimum())/map_unit_per_pixel)
- nb_div = 10
- dw, dh = width/nb_div, height/nb_div
- dx, dy = ((ext.xMaximum()-ext.xMinimum())/nb_div,
- (ext.yMaximum()-ext.yMinimum())/nb_div)
-
- for i in range(nb_div+2):
- painter.drawText(5, int(i*dh), "%.0f" % (ext.yMaximum()-i*dy))
- painter.drawLine(50, int(i*dh), 60, int(i*dh))
- for i in range(nb_div+2):
- painter.drawText(int(i*dw), 20, "%.0f" % (ext.xMinimum()+i*dx))
- painter.drawLine(int(i*dw), 20, int(i*dw), 25)
-
- return True
- except Exception as e:
- self.__drawException.emit(traceback.format_exc(e))
- return False
diff --git a/data/nt.zip b/data/nt.zip
index 1526b0c..263d071 100644
Binary files a/data/nt.zip and b/data/nt.zip differ
diff --git a/doc/__main__.py b/doc/__main__.py
index c8988ed..72d7164 100644
--- a/doc/__main__.py
+++ b/doc/__main__.py
@@ -10,6 +10,7 @@
"""
+from builtins import str
import sys
import getopt
from . import build
diff --git a/elementary_volume/__init__.py b/elementary_volume/__init__.py
index bd014d2..30983eb 100644
--- a/elementary_volume/__init__.py
+++ b/elementary_volume/__init__.py
@@ -1,4 +1,9 @@
# coding = utf-8
+from builtins import next
+from builtins import str
+from builtins import zip
+from builtins import range
+from builtins import object
import os
import random
from itertools import combinations
@@ -159,7 +164,7 @@ def linemerge(lines):
return merged
def has_proper_2d_topology(line):
- SIN_MIN_ANGLE = 5.*PI/180
+ SIN_MIN_ANGLE = .01*PI/180
l = line
if len(l) <=2 :
return False
@@ -190,21 +195,36 @@ def offset_coords(offsets, coords):
return [offsets[c] if c in offsets else c for c in coords]
-def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end_ids_, end_geoms_, srid_=32632):
+def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end_ids_, end_geoms_, end_holes_, srid_=32632, end_node_relative_distance=0.3, end_node_relative_thickness=.3):
DEBUG = False
- PRECI = 9
- REL_DISTANCE = .3
- HEIGHT = 1.
+ PRECI = 6
debug_files = []
nodes = {id_: wkb.loads(bytes.fromhex(geom)) for id_, geom in zip(node_ids_, nodes_)}
ends = defaultdict(list)
- for id_, geom in zip(end_ids_, end_geoms_):
+ end_holes = defaultdict(list)
+ for id_, geom, hole_id in zip(end_ids_, end_geoms_, end_holes_):
ends[id_].append(wkb.loads(bytes.fromhex(geom)))
+ end_holes[id_].append(hole_id)
holes = {n: h for n, h in zip(node_ids_, hole_ids_)}
edges = [(s, e) for s, e in zip(starts_, ends_)]
- assert(len(edges) == len(set(edges)))
+ #assert(len(edges) == len(set(edges)))
+ #assert(len(holes_) == 3)
+ #assert(set(hole_ids_).intersection(set(holes_)) == set(hole_ids_))
+ #assert(set(end_holes_).intersection(set(holes_)) == set(end_holes_))
+
+
+ # translate everything close to origin to avoid numerical issues
+ translation = None
+ for id_ in nodes.keys():
+ if translation is None:
+ translation = nodes[id_].coords[0]
+ nodes[id_] = translate(nodes[id_], -translation[0], -translation[1], -translation[2])
+
+ for id_ in ends.keys():
+ for i in range(len(ends[id_])):
+ ends[id_][i] = translate(ends[id_][i], -translation[0], -translation[1], -translation[2])
graph = defaultdict(set) # undirected (edge in both directions)
for e in edges:
@@ -231,8 +251,6 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
triangle_edges.add(tri[0:1]+tri[2:3])
triangle_nodes.update(tri)
- result = []
- termination = []
# compute face offset direction for termination corners
@@ -240,21 +258,23 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
# and that have at leat 2 incident edges that are not in the same
# face (i.e. different holes)
unused_nodes = set(nodes.keys()).difference(triangle_nodes)
- offsets = {nodes[n].coords[0]: ends[n][0].coords[0] for n, l in ends.items() if len(l)==1}
- offsets.update({nodes[n].coords[-1]: ends[n][0].coords[-1] for n, l in ends.items() if len(l)==1})
+ offsets = {nodes[n].coords[0]: ends[n][0].coords[0] for n, l in list(ends.items()) if len(l)==1}
+ offsets.update({nodes[n].coords[-1]: ends[n][0].coords[-1] for n, l in list(ends.items()) if len(l)==1})
for n in unused_nodes:
p = pair_of_non_coplanar_neighbors(n, graph, holes)
if p:
A, B, C = array(nodes[n].coords[0][:2]), array(nodes[p[0]].coords[0][:2]),array(nodes[p[1]].coords[0][:2])
c = average(array(nodes[n].coords), (0,))
- u = .5*(normalized(B-A)+normalized(C-A))*REL_DISTANCE*.5*(norm(B-A)+norm(C-A))
- offsets[nodes[n].coords[0]] = tuple(c+array((u[0], u[1], +.5*HEIGHT)))
- offsets[nodes[n].coords[-1]] = tuple(c+array((u[0], u[1], -.5*HEIGHT)))
+ u = .5*(normalized(B-A)+normalized(C-A))*end_node_relative_distance*.5*(norm(B-A)+norm(C-A))
+ thickness = abs(nodes[n].coords[0][2] - nodes[n].coords[-1][2])
+ end_node_thickness = end_node_relative_thickness*thickness
+ offsets[nodes[n].coords[0]] = tuple(c+array((u[0], u[1], +.5*end_node_thickness)))
+ offsets[nodes[n].coords[-1]] = tuple(c+array((u[0], u[1], -.5*end_node_thickness)))
if DEBUG:
open('/tmp/offsets.vtk', 'w').write(
- to_vtk(MultiLineString([n for l in ends.values() for n in l]).wkb_hex))
+ to_vtk(MultiLineString([n for l in list(ends.values()) for n in l]).wkb_hex))
sorted_holes = sorted(holes_)
# face origin is the lowest bottom of the node in the first hole
@@ -262,14 +282,18 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
face_idx = -1
lines = []
- for hl, hr in ((sorted_holes[0], sorted_holes[1]),
- (sorted_holes[1], sorted_holes[2]),
- (sorted_holes[0], sorted_holes[2])):
+ faces = defaultdict(list)
+ result = []
+ termination = []
+ for hl, hr, other_hole in (
+ (sorted_holes[0], sorted_holes[1], sorted_holes[2]),
+ (sorted_holes[1], sorted_holes[2], sorted_holes[0]),
+ (sorted_holes[0], sorted_holes[2], sorted_holes[1])):
face_idx += 1
direct_orientation = (hl, hr) == (holes_[0], holes_[1]) or (hl, hr) == (holes_[1], holes_[2]) or (hl, hr) == (holes_[2], holes_[0])
face_edges = list(set([(s, e) if holes[s] == hl else (e, s)
- for s in graph.keys() for e in graph[s] if holes[s] in (hl, hr) and holes[e] in (hl, hr)]))
+ for s in list(graph.keys()) for e in graph[s] if holes[s] in (hl, hr) and holes[e] in (hl, hr)]))
if not len(face_edges):
continue
@@ -280,15 +304,16 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
face_lines.append(Line([nodes[e[0]].coords[1], nodes[e[1]].coords[1]], Line.BOTTOM))
# split lines
- for i, j in combinations(range(len(face_lines)), 2):
+ for i, j in combinations(list(range(len(face_lines))), 2):
assert(face_lines[i].side != Line.VERTICAL and face_lines[j].side != Line.VERTICAL)
p = sym_split(face_lines[i].points, face_lines[j].points)
if p and p not in offsets:
if face_lines[i].points[0] in offsets and face_lines[i].points[-1] in offsets\
and face_lines[j].points[0] in offsets and face_lines[j].points[-1] in offsets:
- offsets[p] = sym_split(
+ splt = sym_split(
offset_coords(offsets, [face_lines[i].points[0], face_lines[i].points[-1]]),
offset_coords(offsets, [face_lines[j].points[0], face_lines[j].points[-1]]))
+ offsets[p] = splt if splt else p
else:
offsets[p] = p
@@ -302,7 +327,7 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
else:
offsets[p] = p
- for k, n in nodes.items():
+ for k, n in list(nodes.items()):
if holes[k] in (hl, hr):
face_lines.append(Line([n.coords[0], n.coords[1]], Line.VERTICAL))
@@ -340,7 +365,8 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
bug = 0
for i, li in enumerate(linework):
if li.length <= 0:
- print('zero length line', i, li.wkt)
+ # fix_print_with_import
+ print(('zero length line', i, li.wkt))
bug = True
break
found = False
@@ -348,7 +374,8 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
if i!=j and (not (lj.coords[0] != li.coords[0] or lj.coords[1] != li.coords[1]) \
or not (lj.coords[0] != li.coords[1] or lj.coords[1] != li.coords[0])):
open("/tmp/dup_line_{}_face_{}.vtk".format(bug, face_idx), 'w').write(to_vtk(MultiLineString([LineString(linework_sav[j])]).wkb_hex))
- print('duplicate line', li.wkt, lj.wkt)
+ # fix_print_with_import
+ print(('duplicate line', li.wkt, lj.wkt))
bug += 1
if i!=j and li.coords[1] == lj.coords[0] or li.coords[1] == lj.coords[1]:
found = True
@@ -356,7 +383,8 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
print(MultiLineString(linework).wkt)
bug += 1
if bug:
- print('open', MultiLineString(linework).wkt)
+ # fix_print_with_import
+ print(('open', MultiLineString(linework).wkt))
assert(False)
@@ -383,17 +411,19 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
term_tri.append(q)
result += domain_tri
+ faces[(hl, hr)] += domain_tri
top_lines = [l for l in face_lines if l.side==Line.TOP]
bottom_lines = [l for l in face_lines if l.side==Line.BOTTOM]
- end_lines = [tuple(nodes[n].coords) for n in ends.keys()]
+ end_lines = {tuple(nodes[n].coords): holes[n] for n in list(ends.keys())}
if DEBUG:
open('/tmp/top_lines_face_{}.vtk'.format(face_idx), 'w').write(to_vtk(MultiLineString([l.points for l in top_lines]).wkb_hex))
open('/tmp/bottom_lines_face_{}.vtk'.format(face_idx), 'w').write(to_vtk(MultiLineString([l.points for l in bottom_lines]).wkb_hex))
open('/tmp/offsets_bis.vtk', 'w').write(
- to_vtk(MultiLineString([LineString([k, v]) for k, v in offsets.items()]).wkb_hex))
+ to_vtk(MultiLineString([LineString([k, v]) for k, v in list(offsets.items())]).wkb_hex))
# create terminations
+ terms = []
edges = set()
for t in term_tri:
for s, e in zip(t.exterior.coords[:-1], t.exterior.coords[1:]):
@@ -409,21 +439,24 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
break
if share:
continue
- termination.append(t)
- termination.append(Polygon(offset_coords(offsets, t.exterior.coords[::-1])))
+ terms.append(t)
+ faces[(hl, hr)] += [t]
+ terms.append(Polygon(offset_coords(offsets, t.exterior.coords[::-1])))
for s in zip(t.exterior.coords[:-1], t.exterior.coords[1:]):
if s in edges:
if (is_segment(s, top_lines) or is_segment(s, bottom_lines) or s in end_lines)\
and s[0] in offsets and s[1] in offsets:
- termination.append(Polygon([offsets[s[0]], s[1], s[0]]))
- termination.append(Polygon([offsets[s[0]], offsets[s[1]], s[1]]))
+ terms.append(Polygon([offsets[s[0]], s[1], s[0]]))
+ terms.append(Polygon([offsets[s[0]], offsets[s[1]], s[1]]))
if (s[1], s[0]) in end_lines:
- termination.append(Polygon([s[1], s[0], offsets[s[1]]]))
- termination.append(Polygon([s[0], offsets[s[0]], offsets[s[1]]]))
+ terms.append(Polygon([s[1], s[0], offsets[s[1]]]))
+ terms.append(Polygon([s[0], offsets[s[0]], offsets[s[1]]]))
+ faces[tuple(sorted((end_lines[(s[1], s[0])], other_hole)))] += terms[-2:]
+ termination += terms
if DEBUG:
open("/tmp/faces.obj", 'w').write(to_obj(MultiPolygon(result).wkb_hex))
- open("/tmp/term.obj", 'w').write(to_obj(MultiPolygon(termination).wkb_hex))
+ open("/tmp/termination.obj", 'w').write(to_obj(MultiPolygon(termination).wkb_hex))
if len(result):
@@ -456,6 +489,7 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
if DEBUG:
open("/tmp/linework_%s.vtk"%(face), 'w').write(to_vtk(MultiLineString([LineString(e) for e in merged]).wkb_hex))
+ face_triangles = []
for m in merged:
if has_proper_2d_topology(m):
node_map = {(round(x[0], PRECI), round(x[1], PRECI)): x for x in m}
@@ -468,13 +502,21 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
if face == 'bottom' else \
Polygon([node_map[tri[2]], node_map[tri[1]], node_map[tri[0]]])
result.append(q)
+ face_triangles.append(q)
+ if DEBUG:
+ open("/tmp/face_{}.obj".format(face), 'w').write(to_obj(MultiPolygon(face_triangles).wkb_hex))
+
# adds isolated nodes terminations
- for n, l in ends.items():
+ for n, l in list(ends.items()):
if len(l) == 2:
node = nodes[n]
A, B, C = array(node.coords[0]), array(l[0].coords[0]), array(l[1].coords[0])
- l = l if dot(cross(B-A, C-A), array((0.,0.,1.))) > 0 else list(reversed(l))
+ k1, k2 = tuple(sorted((holes[n], end_holes[n][0]))), tuple(sorted((holes[n], end_holes[n][1])))
+ l = l
+ if dot(cross(B-A, C-A), array((0.,0.,1.))) <= 0:
+ l = list(reversed(l))
+ k1, k2 = k2, k1
termination += [
Polygon([node.coords[0], l[0].coords[0], l[1].coords[0]]),
Polygon([l[1].coords[-1], l[0].coords[-1], node.coords[-1]]),
@@ -485,9 +527,23 @@ def elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end
Polygon([l[0].coords[0], l[0].coords[1], l[1].coords[0]]),
Polygon([l[0].coords[1], l[1].coords[1], l[1].coords[0]])
]
+ assert(len(end_holes[n])==2)
+ faces[k1] += [
+ Polygon([node.coords[0], node.coords[1], l[0].coords[0]]),
+ Polygon([node.coords[1], l[0].coords[1], l[0].coords[0]]),
+ ]
+ faces[k2] += [
+ Polygon([l[1].coords[0], node.coords[1], node.coords[0]]),
+ Polygon([l[1].coords[0], l[1].coords[1], node.coords[1]]),
+ ]
result += termination
+ if DEBUG:
+ for hp, tri in faces.items():
+ open("/tmp/face_{}_{}.obj".format(hp[0], hp[1]), 'w').write(to_obj(MultiPolygon([t for t in tri]).wkb_hex))
+
+
# decompose volume in connected components
edges = {}
graph = {i:set() for i in range(len(result))}
@@ -510,13 +566,75 @@ def pop_connected(n, graph):
connected = []
while len(graph):
- n = next(iter(graph.keys()))
+ n = next(iter(list(graph.keys())))
connected.append(pop_connected(n, graph))
+ i=0
for c in connected:
- r = MultiPolygon([result[i] for i in c])
- geos.lgeos.GEOSSetSRID(r._geom, srid_)
- yield r.wkb_hex
+ i+=1
+ face1 = []
+ face2 = []
+ face3 = []
+ triangles = [result[i] for i in c]
+ res = MultiPolygon(triangles)
+
+ for f in faces[(sorted_holes[0], sorted_holes[1])]:
+ if f in triangles:
+ face1.append(f)
+ for f in faces[(sorted_holes[1], sorted_holes[2])]:
+ if f in triangles:
+ face2.append(f)
+ for f in faces[(sorted_holes[0], sorted_holes[2])]:
+ if f in triangles:
+ face3.append(f)
+
+ if DEBUG:
+ open("/tmp/face1_tr_%d.obj"%(i), 'w').write(to_obj(face1.wkb_hex))
+ open("/tmp/face2_tr_%d.obj"%(i), 'w').write(to_obj(face2.wkb_hex))
+ open("/tmp/face3_tr_%d.obj"%(i), 'w').write(to_obj(face3.wkb_hex))
+ open("/tmp/volume_tr.obj", 'w').write(to_obj(res.wkb_hex))
+ # check volume is closed
+ edges = set()
+ for p in res:
+ for s, e in zip(p.exterior.coords[:-1], p.exterior.coords[1:]):
+ if (e, s) in edges:
+ edges.remove((e, s))
+ else:
+ edges.add((s, e))
+ if len(edges):
+ print("volume is not closed", edges)
+ open("/tmp/unconnected_edge.vtk", 'w').write(to_vtk(MultiLineString([LineString(e) for e in edges]).wkb_hex))
+
+
+ # check volume is positive
+ volume = 0
+ for p in res:
+ r = p.exterior.coords
+ v210 = r[2][0]*r[1][1]*r[0][2];
+ v120 = r[1][0]*r[2][1]*r[0][2];
+ v201 = r[2][0]*r[0][1]*r[1][2];
+ v021 = r[0][0]*r[2][1]*r[1][2];
+ v102 = r[1][0]*r[0][1]*r[2][2];
+ v012 = r[0][0]*r[1][1]*r[2][2];
+ volume += (1./6.)*(-v210 + v120 + v201 - v021 - v102 + v012)
+ if volume <= 0 :
+ print("volume is", volume)
+
+ res = translate(res, translation[0], translation[1], translation[2])
+ geos.lgeos.GEOSSetSRID(res._geom, srid_)
+
+ face1 = translate(MultiPolygon(face1), translation[0], translation[1], translation[2])
+ geos.lgeos.GEOSSetSRID(face1._geom, srid_)
+
+ face2 = translate(MultiPolygon(face2), translation[0], translation[1], translation[2])
+ geos.lgeos.GEOSSetSRID(face2._geom, srid_)
+
+ face3 = translate(MultiPolygon(face3), translation[0], translation[1], translation[2])
+ geos.lgeos.GEOSSetSRID(face3._geom, srid_)
+
+ empty_mp = "SRID={} ;MULTIPOLYGONZ EMPTY".format(srid_)
+ yield (res.wkb_hex if not res.is_empty else empty_mp, face1.wkb_hex if not face1.is_empty else empty_mp,
+ face2.wkb_hex if not face2.is_empty else empty_mp, face3.wkb_hex if not face3.is_empty else empty_mp)
for f in debug_files:
os.remove(f)
diff --git a/elementary_volume/__main__.py b/elementary_volume/__main__.py
index 86df4f5..654b5da 100644
--- a/elementary_volume/__main__.py
+++ b/elementary_volume/__main__.py
@@ -13,7 +13,11 @@
nodes_ = f.readline().rstrip().split()
end_ids_ = f.readline().rstrip().split()
end_geoms_ = f.readline().rstrip().split()
+ end_holes_ = f.readline().rstrip().split()
idx = 0
- for v in elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end_ids_, end_geoms_):
+ for v, f1, f2, f3 in elementary_volumes(holes_, starts_, ends_, hole_ids_, node_ids_, nodes_, end_ids_, end_geoms_, end_holes_):
open("/tmp/volume%d.obj"%(idx), 'w').write(to_obj(v))
+ open("/tmp/face1_%d.obj"%(idx), 'w').write(to_obj(f1))
+ open("/tmp/face2_%d.obj"%(idx), 'w').write(to_obj(f2))
+ open("/tmp/face3_%d.obj"%(idx), 'w').write(to_obj(f3))
idx += 1
diff --git a/export_elementary_volume.py b/export_elementary_volume.py
index 8d26407..3e8e872 100644
--- a/export_elementary_volume.py
+++ b/export_elementary_volume.py
@@ -1,8 +1,9 @@
import os
-from PyQt4 import uic
-from PyQt4.QtCore import Qt
-from PyQt4.QtGui import QDialog, QFileDialog, QApplication, QCursor
+from qgis.PyQt import uic
+from qgis.PyQt.QtCore import Qt
+from qgis.PyQt.QtWidgets import QDialog, QFileDialog, QApplication
+from qgis.PyQt.QtGui import QCursor
from qgis.core import QgsFeatureRequest
@@ -46,36 +47,20 @@ def __export(self):
QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
QApplication.processEvents()
- for fid in fids:
- request = QgsFeatureRequest(fid)
-
- ft = None
- for feature in self.cell_layer.getFeatures(request):
- ft = feature
-
- if not ft:
- return
-
- cell = ft["id"]
- outdir = self.mOutputDir.text()
-
- if self.mFormat.currentText() == "OBJ":
- self.project.export_elementary_volume_obj(
- self.graph, cell, outdir, True
- )
- else: # DXF
- self.project.export_elementary_volume_dxf(
- self.graph, cell, outdir, True
- )
-
- if not closed_only:
- if self.mFormat.currentText() == "OBJ":
- self.project.export_elementary_volume_obj(
- self.graph, cell, outdir, False
- )
- else: # DXF
- self.project.export_elementary_volume_dxf(
- self.graph, cell, outdir, False
- )
+ cell_ids = [feature["id"]
+ for fid in fids
+ for feature in self.cell_layer.getFeatures(QgsFeatureRequest(fid))
+ ]
+
+ outdir = self.mOutputDir.text()
+
+ if self.mFormat.currentText() == "OBJ":
+ self.project.export_elementary_volume_obj(
+ self.graph, cell_ids, outdir, closed_only
+ )
+ else: # DXF
+ self.project.export_elementary_volume_dxf(
+ self.graph, cell_ids, outdir, closed_only
+ )
QApplication.restoreOverrideCursor()
diff --git a/import_test.py b/import_test.py
deleted file mode 100644
index 184d4ff..0000000
--- a/import_test.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# coding = utf-8
-
-if __name__ == "__main__":
- from albion.project import Project
- import os
- import sys
- import time
-
-
- project_name = "import_test"
- if Project.exists(project_name):
- Project.delete(project_name)
-
- project = Project.create(project_name, 32632)
- start = time.time()
- project.import_data(sys.argv[1])
- print "time for import", time.time() - start, 'sec'
- #project = Project(project_name)
- #
- #project.triangulate()
- #project.create_section_view_0_90(4)
-
diff --git a/log_strati.py b/log_strati.py
index dc0d40f..63d2e86 100644
--- a/log_strati.py
+++ b/log_strati.py
@@ -1,10 +1,12 @@
# coding=utf-8
-from qgis.core import QgsDataSourceURI
+from builtins import str
+from builtins import range
-from PyQt4 import uic
-from PyQt4.QtGui import QGraphicsScene, QImage, QPixmap, QMainWindow, QBrush, QColor, QWheelEvent, QPen
-from PyQt4.QtCore import Qt, QObject
+from qgis.PyQt import uic
+from qgis.PyQt.QtWidgets import QGraphicsScene, QMainWindow
+from qgis.PyQt.QtGui import QImage, QPixmap, QBrush, QColor, QPen
+from qgis.PyQt.QtCore import Qt, QObject
from shapely import wkb
import os
@@ -227,8 +229,8 @@ def __init__(self, conn_info, parent=None):
if __name__=='__main__':
import sys
- from PyQt4.QtCore import QSettings
- from PyQt4.QtGui import QApplication
+ from qgis.PyQt.QtCore import QSettings
+ from qgis.PyQt.QtWidgets import QApplication
QApplication.setOrganizationName("QGIS")
QApplication.setOrganizationDomain("qgis.org")
diff --git a/metadata.txt b/metadata.txt
index e4ac93f..ccf4c9c 100644
--- a/metadata.txt
+++ b/metadata.txt
@@ -1,8 +1,8 @@
[general]
name=Albion
-qgisMinimumVersion=2.14
+qgisMinimumVersion=3.2
description=Build 3D geological model from wells information
-version=3.0.0
+version=2.2.0
author=Oslandia
email=infos@oslandia.com
experimental=False
diff --git a/mineralization.py b/mineralization.py
index 8c7854d..fac5786 100644
--- a/mineralization.py
+++ b/mineralization.py
@@ -1,7 +1,7 @@
# coding = utf-8
import qgis.core
-from PyQt4.QtGui import QDialog
-from PyQt4 import uic
+from qgis.PyQt.QtWidgets import QDialog
+from qgis.PyQt import uic
import os
class MineralizationDialog(QDialog):
@@ -15,7 +15,7 @@ def accept(self):
self.close()
if __name__=="__main__":
- from PyQt4.QtGui import QApplication
+ from qgis.PyQt.QtWidgets import QApplication
import sys
from albion.project import Project
diff --git a/package.py b/package.py
index 0650b67..725d114 100644
--- a/package.py
+++ b/package.py
@@ -19,7 +19,9 @@
-t
launch the tests before installing/uninstalling
"""
+from __future__ import print_function
+from builtins import str
import os
import zipfile
import re
@@ -30,7 +32,7 @@
# @todo make that work on windows
-qgis_plugin_dir = os.path.join(os.path.expanduser("~"), ".qgis2", "python", "plugins")
+qgis_plugin_dir = os.path.join(os.path.expanduser("~"), ".local", "share", "QGIS", "QGIS3", "profiles", "default", "python", "plugins")
zipname = "albion"
zipext = ".zip"
diff --git a/plugin.py b/plugin.py
index a0458f2..8ad4475 100644
--- a/plugin.py
+++ b/plugin.py
@@ -1,25 +1,12 @@
# coding: utf-8
+from builtins import str
from qgis.core import *
from qgis.gui import *
-from PyQt4.QtCore import QObject, Qt, QFileInfo, QUrl
-from PyQt4.QtGui import (
- QComboBox,
- QShortcut,
- QKeySequence,
- QToolBar,
- QIcon,
- QMenu,
- QFileDialog,
- QInputDialog,
- QLineEdit,
- QMessageBox,
- QProgressBar,
- QApplication,
- QDockWidget,
- QDesktopServices,
-)
+from qgis.PyQt.QtCore import QObject, Qt, QUrl
+from qgis.PyQt.QtWidgets import QComboBox, QShortcut, QToolBar, QMenu, QFileDialog, QInputDialog, QLineEdit, QMessageBox, QProgressBar, QApplication, QDockWidget
+from qgis.PyQt.QtGui import QKeySequence, QIcon, QDesktopServices
import psycopg2
import os
@@ -29,10 +16,9 @@
from .project import ProgressBar, Project, find_in_dir
from .mineralization import MineralizationDialog
-from .axis_layer import AxisLayer, AxisLayerType
from .viewer_3d.viewer_3d import Viewer3d
from .viewer_3d.viewer_controls import ViewerControls
-from .log_strati import BoreHoleWindow
+#from .log_strati import BoreHoleWindow
from .export_elementary_volume import ExportElementaryVolume
@@ -42,13 +28,6 @@
import atexit
-AXIS_LAYER_TYPE = AxisLayerType()
-QgsPluginLayerRegistry.instance().addPluginLayerType(AXIS_LAYER_TYPE)
-atexit.register(
- QgsPluginLayerRegistry.instance().removePluginLayerType, AxisLayer.LAYER_TYPE
-)
-
-
def resource(name):
"""Return name with prepended `res` directory
"""
@@ -71,7 +50,6 @@ def __init__(self, iface):
self.__current_graph = QComboBox()
self.__current_graph.setMinimumWidth(150)
self.__toolbar = None
- self.__axis_layer = None
self.__menu = None
self.__log_strati = None
@@ -79,9 +57,10 @@ def initGui(self):
for keyseq, slot in (
(Qt.CTRL + Qt.ALT + Qt.Key_K, self.__create_group),
- (Qt.CTRL + Qt.ALT + Qt.Key_S, self.__select_next_group),
+# (Qt.CTRL + Qt.ALT + Qt.Key_S, self.__select_next_group),
(Qt.CTRL + Qt.ALT + Qt.Key_N, self.__next_section),
(Qt.CTRL + Qt.ALT + Qt.Key_B, self.__previous_section),
+ (Qt.CTRL + Qt.ALT + Qt.Key_J, self.__add_section_from_selection),
):
short = QShortcut(QKeySequence(keyseq), self.__iface.mainWindow())
@@ -96,28 +75,38 @@ def initGui(self):
self.__toolbar = QToolBar("Albion")
self.__iface.addToolBar(self.__toolbar)
- self.__toolbar.addAction(
- icon("log_strati.svg"), "stratigraphic log"
- ).triggered.connect(self.__log_strati_clicked)
+ #self.__toolbar.addAction(
+ # icon("log_strati.svg"), "stratigraphic log"
+ #).triggered.connect(self.__log_strati_clicked)
self.__toolbar.addWidget(self.__current_graph)
- self.__current_graph.currentIndexChanged[unicode].connect(
+ self.__current_graph.currentIndexChanged[str].connect(
self.__current_graph_changed
)
self.__toolbar.addWidget(self.__current_section)
- self.__current_section.currentIndexChanged[unicode].connect(
+ self.__current_section.currentIndexChanged[str].connect(
self.__current_section_changed
)
self.__toolbar.addAction(
- icon("previous_line.svg"), "previous section (Ctrl+Alt+b)"
+ icon("previous_line_big.svg"), "previous section (Ctrl+Alt+b)"
).triggered.connect(self.__previous_section)
+
+ self.__toolbar.addAction(
+ icon("previous_line.svg"), "previous sub section"
+ ).triggered.connect(self.__previous_subsection)
+
+ self.__toolbar.addAction(
+ icon("next_line.svg"), "next sub section"
+ ).triggered.connect(self.__next_subsection)
+
self.__toolbar.addAction(
- icon("next_line.svg"), "next section (Ctrl+Alt+n)"
+ icon("next_line_big.svg"), "next section (Ctrl+Alt+n)"
).triggered.connect(self.__next_section)
+
self.__toolbar.addAction(
icon("line_from_selected.svg"), "create temporary section"
).triggered.connect(self.__section_from_selection)
@@ -156,107 +145,122 @@ def __add_menu_entry(self, name, callback, enabled=True, help_str=""):
return act
def __create_menu_entries(self):
+
self.__menu.clear()
+
self.__add_menu_entry("New &Project", self.__new_project)
+
self.__add_menu_entry("Import Project", self.__import_project)
+
+ self.__add_menu_entry("Export Project", self.__export_project, self.project is not None)
+
self.__add_menu_entry("Upgrade Project", self.__upgrade_project)
self.__menu.addSeparator()
self.__add_menu_entry(
- "&Import Data",
+ "&Import directory",
self.__import_data,
self.project is not None,
- "Import data from directory. The data files are in ",
+ "Import data from directory"
)
- self.__menu.addSeparator()
-
self.__add_menu_entry(
- "Create cells",
- self.__create_cells,
- self.project is not None and self.project.has_collar,
- "Create Delaunay triangulation of collar layer.",
+ "&Import holes",
+ None, #self.__import_holes,
+ self.project is not None and False,
+ "Import hole data from directory"
)
self.__add_menu_entry(
- "Refresh all edges",
- self.__refresh_all_edge,
- self.project is not None and self.project.has_cell,
- "Refresh materialized view of all cell edges used by graph possible edges.",
+ "Export holes",
+ self.__export_holes,
+ self.project is not None and self.project.has_hole,
+ "Export hole trace in .vtk or .dxf format",
)
self.__add_menu_entry(
- "Refresh diagraphy",
- self.__refresh_diagraphy,
+ "Import layer",
+ self.__import_layer,
self.project is not None,
- "Refresh materialized view of radiometry and resistivity.",
+ "Import data from selected layer."
+ )
+
+ self.__add_menu_entry(
+ "Export layer",
+ self.__export_layer,
+ self.project is not None
+ )
+
+ self.__add_menu_entry(
+ "Compute &Mineralization",
+ self.__compute_mineralization,
+ self.project is not None and self.project.has_radiometry,
+ "",
)
+ self.__menu.addSeparator()
self.__menu.addSeparator()
- # self.__add_menu_entry(u'Create section views 0° and 90°', self.__create_section_view_0_90,
- # False and self.project is not None and self.project.has_hole,
- # "Create section views (i.e. cut directions) to work West-East and South-North for this project")
- # self.__add_menu_entry(u'Create section views -45° and 45°', None,
- # False and self.project is not None and self.project.has_hole,
- # "Create section views (i.e. cut directions) to work SE-NW and SW-NE for this project")
- #
- # self.__menu.addSeparator()
+ self.__add_menu_entry(
+ "Create cells",
+ self.__create_cells,
+ self.project is not None and self.project.has_hole,
+ "Create Delaunay triangulation of collar layer.",
+ )
self.__add_menu_entry(
- "Create sections",
+ "Create subsections",
self.__create_sections,
self.project is not None and self.project.has_group_cell,
"Once cell groups have been defined, create section lines.",
)
- self.__menu.addSeparator()
-
self.__add_menu_entry(
- "Compute &Mineralization",
- self.__compute_mineralization,
- self.project is not None and self.project.has_radiometry,
- "",
+ "Refresh selected layers sections",
+ self.__refresh_selected_layers_sections,
+ self.project is not None,
+ ""
)
+
self.__menu.addSeparator()
+
self.__add_menu_entry(
"New &Graph",
self.__new_graph,
self.project is not None,
- "Create a new grap.h",
+ "Create a new graph",
)
+
self.__add_menu_entry(
- "Delete Graph", self.__delete_graph, self.project is not None
+ "Delete Graph", self.__delete_graph, self.project is not None and self.project.has_graph
)
- self.__menu.addSeparator()
+
self.__add_menu_entry(
- "Create volumes",
- self.__create_volumes,
- self.project is not None and bool(self.__current_graph.currentText()),
- "Create volumes associated with current graph.",
+ "Add selection to graph nodes", self.__add_selection_to_graph_node, self.project is not None and self.project.has_graph
+
)
- self.__menu.addSeparator()
+
+ self.__add_menu_entry(
+ "Accept graph possible edges", self.__accept_possible_edge, self.project is not None and self.project.has_graph
+ )
+
self.__add_menu_entry(
"Create terminations",
self.__create_terminations,
self.project is not None and bool(self.__current_graph.currentText()),
"Create terminations associated with current graph.",
)
- self.__menu.addSeparator()
- self.__add_menu_entry("Toggle axis", self.__toggle_axis)
self.__menu.addSeparator()
-
- self.__add_menu_entry(
- "Export Project", self.__export_project, self.project is not None
- )
+
self.__add_menu_entry(
- "Export Sections",
- None,
- self.project is not None and self.project.has_section,
- "Export triangulated section in .obj or .dxf format",
+ "Create volumes",
+ self.__create_volumes,
+ self.project is not None and bool(self.__current_graph.currentText()),
+ "Create volumes associated with current graph.",
)
+
self.__add_menu_entry(
"Export Volume",
self.__export_volume,
@@ -271,6 +275,13 @@ def __create_menu_entries(self):
"Export an elementary volume of current graph in .obj or .dxf format",
)
+ self.__add_menu_entry(
+ "Export Sections",
+ self.__export_sections,
+ self.project is not None and bool(self.__current_graph.currentText()) and self.project.has_section and self.project.has_volume,
+ "Export triangulated section in .obj or .dxf format",
+ )
+
self.__menu.addSeparator()
self.__menu.addAction("Help").triggered.connect(self.open_help)
@@ -289,45 +300,49 @@ def __getattr__(self, name):
else:
raise AttributeError(name)
- def __refresh_all_edge(self):
- if self.project is None:
- return
- self.project.refresh_all_edge()
-
- def __refresh_diagraphy(self):
- if self.project:
- self.project.refresh_radiometry()
- self.project.refresh_resistivity()
-
def __create_terminations(self):
- if self.project is None:
- return
self.project.create_terminations(self.__current_graph.currentText())
self.__viewer3d.widget().refresh_data()
self.__refresh_layers("section")
def __create_volumes(self):
- if self.project is None:
- return
self.project.create_volumes(self.__current_graph.currentText())
self.__viewer3d.widget().refresh_data()
def __next_section(self):
- if self.project is None:
- return
self.project.next_section(self.__current_section.currentText())
self.__refresh_layers("section")
self.__viewer3d.widget().scene.update("section")
+ self.__viewer3d.widget().scene.update("volume_section")
self.__viewer3d.widget().update()
def __previous_section(self):
- if self.project is None:
- return
self.project.previous_section(self.__current_section.currentText())
self.__refresh_layers("section")
self.__viewer3d.widget().scene.update("section")
+ self.__viewer3d.widget().scene.update("volume_section")
self.__viewer3d.widget().update()
+ def __next_subsection(self):
+ self.project.next_subsection(self.__current_section.currentText())
+ print("refresh")
+ self.__refresh_layers("section")
+ print("section")
+ self.__viewer3d.widget().scene.update("section")
+ print("volume section")
+ self.__viewer3d.widget().scene.update("volume_section")
+ print("3D update")
+ self.__viewer3d.widget().update()
+ print("done done")
+
+ def __previous_subsection(self):
+ self.project.previous_subsection(self.__current_section.currentText())
+ self.__refresh_layers("section")
+ self.__viewer3d.widget().scene.update("section")
+ self.__viewer3d.widget().scene.update("volume_section")
+ self.__viewer3d.widget().update()
+
+
def __refresh_layers(self, name=None, updateExtent=False):
for layer in self.__iface.mapCanvas().layers():
if name is None or layer.name().find(name) != -1:
@@ -343,26 +358,24 @@ def __layer(self, name):
return lay
def __current_section_changed(self, section_id):
- layers = QgsMapLayerRegistry.instance().mapLayersByName(u"group_cell")
+ layers = QgsProject.instance().mapLayersByName(u"group_cell")
if len(layers):
layers[0].setSubsetString("section_id='{}'".format(section_id))
self.__refresh_layers("section")
- def __select_next_group(self):
- if (
- self.project
- and self.__iface.activeLayer()
- and self.__iface.activeLayer().name() == u"cell"
- ):
- self.__iface.activeLayer().removeSelection()
- self.__iface.activeLayer().selectByExpression(
- "id in ({})".format(",".join(project.next_group_ids()))
- )
-
+# def __select_next_group(self):
+# if (
+# self.__iface.activeLayer()
+# and self.__iface.activeLayer().name() == u"cell"
+# ):
+# self.__iface.activeLayer().removeSelection()
+# self.__iface.activeLayer().selectByExpression(
+# "id in ({})".format(",".join(project.next_group_ids()))
+# )
+#
def __create_group(self):
if (
- self.project
- and self.__iface.activeLayer()
+ self.__iface.activeLayer()
and self.__iface.activeLayer().name() == u"cell"
):
if self.__iface.activeLayer().selectedFeatureCount():
@@ -382,7 +395,7 @@ def __qgis__project__loaded(self):
self.__current_section.addItems(self.project.sections())
self.__current_graph.addItems(self.project.graphs())
- layers = QgsMapLayerRegistry.instance().mapLayersByName("section.anchor")
+ layers = QgsProject.instance().mapLayersByName("section.anchor")
if len(layers):
layers[0].editingStopped.connect(self.__update_section_list)
@@ -390,10 +403,11 @@ def __qgis__project__loaded(self):
# We make sure that corresponding extents are valid when the project
# is loaded
- cell = QgsMapLayerRegistry.instance().mapLayersByName("cell")[0]
- cell.updateExtents()
+ cell = QgsProject.instance().mapLayersByName("cell")
+ if len(cell):
+ cell[0].updateExtents()
- section_geom = QgsMapLayerRegistry.instance().mapLayersByName("section.geom")
+ section_geom = QgsProject.instance().mapLayersByName("section.geom")
if section_geom:
section_geom[0].updateExtents()
@@ -411,12 +425,16 @@ def __upgrade_project(self):
)
if not ok:
return
- Project(project_name).update()
+ project = Project(project_name)
+ project.update()
+ QgsProject.instance().writeEntry("albion", "project_name", project.name)
+ QgsProject.instance().writeEntry("albion", "srid", project.srid)
+ self.__qgis__project__loaded()
+
def __new_project(self):
- # @todo open dialog to configure project name and srid
- fil = QFileDialog.getSaveFileName(
+ fil, __ = QFileDialog.getSaveFileName(
None,
u"New project name (no space, plain ascii)",
QgsProject.instance().readEntry("albion", "last_dir", "")[0],
@@ -426,9 +444,7 @@ def __new_project(self):
return
fil = fil if len(fil) > 4 and fil[-4:] == ".qgs" else fil + ".qgs"
fil = fil.replace(" ", "_")
- try:
- fil.decode("ascii")
- except UnicodeDecodeError:
+ if len(fil) != len(fil.encode()):
self.__iface.messageBar().pushError(
"Albion:", "project name may only contain asci character (no accent)"
)
@@ -453,23 +469,30 @@ def __new_project(self):
!= QMessageBox(
QMessageBox.Information,
"Delete existing DB",
- "Database {} exits, to you want to delete it ?".format(
+ "Database {} exits, do you want to delete it ?".format(
project_name
),
QMessageBox.Yes | QMessageBox.No,
).exec_()
):
- return
- Project.delete(project_name)
+ self.__iface.messageBar().pushInfo("Albion:", "keeping existing database...")
+ else:
+ Project.delete(project_name)
+ self.__iface.messageBar().pushInfo("Albion:", "creating project...")
+ Project.create(project_name, srid)
+ else:
+ self.__iface.messageBar().pushInfo("Albion:", "creating project...")
+ Project.create(project_name, srid)
- self.__iface.messageBar().pushInfo("Albion:", "creating project...")
- Project.create(project_name, srid)
+ if os.path.exists(fil):
+ os.remove(fil)
# load template
open(fil, "w").write(
open(resource("template_project.qgs"))
.read()
.replace("template_project", project_name)
+ .replace("32632", str(srid))
)
self.__iface.newProject()
QgsProject.instance().setFileName(fil)
@@ -480,14 +503,12 @@ def __new_project(self):
self.__qgis__project__loaded()
def __import_data(self):
- if self.project is None:
- return
- if not QgsProject.instance().readEntry("albion", "conn_info", "")[0]:
- return
+ assert(self.project)
dir_ = QFileDialog.getExistingDirectory(
None,
u"Data directory",
QgsProject.instance().readEntry("albion", "last_dir", "")[0],
+ QFileDialog.ShowDirsOnly | QFileDialog.DontUseNativeDialog
)
if not dir_:
return
@@ -499,24 +520,23 @@ def __import_data(self):
progress = QProgressBar()
progress.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
progressMessageBar.layout().addWidget(progress)
- self.__iface.messageBar().pushWidget(
- progressMessageBar, self.__iface.messageBar().INFO
- )
+ self.__iface.messageBar().pushWidget(progressMessageBar)
self.project.import_data(dir_, ProgressBar(progress))
- self.project.triangulate()
+ #self.project.triangulate()
self.project.create_section_view_0_90(4)
self.__iface.messageBar().clearWidgets()
- collar = QgsMapLayerRegistry.instance().mapLayersByName("collar")[0]
- collar.reload()
- collar.updateExtents()
- self.__iface.setActiveLayer(collar)
- QApplication.instance().processEvents()
- while self.__iface.mapCanvas().isDrawing():
+ collar = QgsProject.instance().mapLayersByName("collar")
+ if len(collar):
+ collar[0].reload()
+ collar[0].updateExtents()
+ self.__iface.setActiveLayer(collar[0])
QApplication.instance().processEvents()
- self.__iface.zoomToActiveLayer()
+ while self.__iface.mapCanvas().isDrawing():
+ QApplication.instance().processEvents()
+ self.__iface.zoomToActiveLayer()
self.__iface.actionSaveProject().trigger()
@@ -524,10 +544,54 @@ def __import_data(self):
self.__current_section.clear()
self.__current_section.addItems(self.project.sections())
- def __new_graph(self):
+ def __import_layer(self):
+ assert(self.project)
+ if self.__iface.activeLayer():
+ from_idx = None
+ to_idx = None
+ hole_id_idx= None
+ other_idx = []
+ definitions = []
+ fields = []
+ for idx, f in enumerate(self.__iface.activeLayer().fields()):
+ if f.name().lower() == 'from' or f.name().lower() == 'from_':
+ from_idx = idx
+ elif f.name().lower() == 'to' or f.name().lower() == 'to_':
+ to_idx = idx
+ elif f.name().lower() == 'hole_id' or f.name().lower() == 'holeid':
+ hole_id_idx = idx
+ else:
+ other_idx.append(idx)
+ name = f.name().lower().replace(' ', '_')
+ fields.append(name)
+ type_ = 'varchar'
+ if f.typeName() == 'double':
+ type_ = 'double precision'
+ elif f.typeName() == 'integer':
+ type_ = 'integer'
+ definitions.append(name + ' ' + type_)
+
+ table = {
+ 'NAME': self.__iface.activeLayer().name().lower().replace(' ', '_'),
+ 'FIELDS_DEFINITION': ', '.join(definitions),
+ 'FIELDS': ', '.join(fields),
+ 'SRID': self.project.srid
+ }
+
+ if from_idx is None or to_idx is None or hole_id_idx is None:
+ self.__iface.messageBar().pushCritical(
+ "Albion", "imported layer must have 'to', 'from' and 'hole_id' fields")
+ return
- if self.project is None:
- return
+ values = []
+ for f in self.__iface.activeLayer().getFeatures():
+ values.append((f[hole_id_idx], f[from_idx], f[to_idx]) +
+ tuple((f[i] for i in other_idx)))
+ self.project.add_table(table, values)
+
+
+
+ def __new_graph(self):
graph, ok = QInputDialog.getText(
self.__iface.mainWindow(),
@@ -556,8 +620,6 @@ def __new_graph(self):
self.__current_graph.setCurrentIndex(self.__current_graph.findText(graph))
def __delete_graph(self):
- if self.project is None:
- return
graph, ok = QInputDialog.getText(
self.__iface.mainWindow(),
@@ -571,38 +633,78 @@ def __delete_graph(self):
return
self.__current_graph.removeItem(self.__current_graph.findText(graph))
+ self.project.delete_graph(graph)
+
+ def __add_selection_to_graph_node(self):
+ assert(self.project)
+ #TODO ADD DIALOG TO REMIND USER THE CURRENT GRAPH
+ if (
+ self.__iface.activeLayer()
+ and self.__iface.activeLayer().selectedFeatures()
+ ):
+ selection = self.__iface.activeLayer().selectedFeatures()
+ graph = self.__current_graph.currentText()
+ if (
+ QMessageBox.Yes
+ != QMessageBox(
+ QMessageBox.Information,
+ "Adding selected edges",
+ "Do you want to add {} selected edges to {} ?".format(
+ len(selection),
+ graph
+ ),
+ QMessageBox.Yes | QMessageBox.No,
+ ).exec_()
+ ):
+ return
+
+ self.project.add_to_graph_node(graph, selection)
- def __toggle_axis(self):
- if self.__axis_layer:
- pass
- QgsMapLayerRegistry.instance().removeMapLayer(self.__axis_layer.id())
- self.__axis_layer = None
- else:
- self.__axis_layer = AxisLayer(
- self.__iface.mapCanvas().mapSettings().destinationCrs()
- )
- QgsMapLayerRegistry.instance().addMapLayer(self.__axis_layer)
self.__refresh_layers()
+ def __accept_possible_edge(self):
+ assert(self.project)
+ self.project.accept_possible_edge(self.__current_graph.currentText())
+
def __create_cells(self):
- if self.project is None:
- return
+ assert(self.project)
+
+ if self.project.has_cell:
+ if (
+ QMessageBox.Yes
+ != QMessageBox(
+ QMessageBox.Information,
+ "Creating cells",
+ "Do you want to replace project cells (your graphs will become invalid) ?",
+ QMessageBox.Yes | QMessageBox.No,
+ ).exec_()
+ ):
+ return
+
self.project.triangulate()
- self.__refresh_layers("cells")
+ self.__refresh_layers()
def __create_sections(self):
- if self.project is None:
- return
+ assert(self.project)
self.project.create_sections()
+ def __refresh_selected_layers_sections(self):
+ assert(self.project)
+ for l in self.__iface.layerTreeView().selectedLayers():
+ uri = QgsDataSourceUri(l.dataProvider().dataSourceUri())
+ table = uri.table()
+ if table.endswith('_section'):
+ table = table[:-8]
+ self.project.refresh_section_geom(table)
+ self.__refresh_layers(table+'_section')
+
def __compute_mineralization(self):
MineralizationDialog(self.project).exec_()
def __export_volume(self):
- if self.project is None:
- return
+ assert(self.project)
- fil = QFileDialog.getSaveFileName(
+ fil, __ = QFileDialog.getSaveFileName(
None,
u"Export volume for current graph",
QgsProject.instance().readEntry("albion", "last_dir", "")[0],
@@ -623,11 +725,13 @@ def __export_volume(self):
)
def __export_elementary_volume(self):
- if self.project is None:
- return
+ assert(self.project)
layer = self.__layer("cell")
if not layer:
+ self.__iface.messageBar().pushWarning(
+ "Albion", "cell layer must be selected"
+ )
return
graph = self.__current_graph.currentText()
@@ -635,8 +739,87 @@ def __export_elementary_volume(self):
export_widget.show()
export_widget.exec_()
+ def __export_sections(self):
+ assert(self.project)
+
+ fil, __ = QFileDialog.getSaveFileName(
+ None,
+ u"Export named sections for current graph",
+ QgsProject.instance().readEntry("albion", "last_dir", "")[0],
+ "File formats (*.dxf *.obj)",
+ )
+ if not fil:
+ return
+
+ QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil))
+
+ if fil[-4:] == ".obj":
+ self.project.export_sections_obj(self.__current_graph.currentText(), fil)
+ elif fil[-4:] == ".dxf":
+ self.project.export_sections_dxf(self.__current_graph.currentText(), fil)
+ else:
+ self.__iface.messageBar().pushWarning(
+ "Albion", "unsupported extension for section export"
+ )
+
+
+ def __export_holes(self):
+ assert(self.project)
+
+ fil, __ = QFileDialog.getSaveFileName(
+ None,
+ u"Export holes",
+ QgsProject.instance().readEntry("albion", "last_dir", "")[0],
+ "File formats (*.dxf *.vtk)",
+ )
+ if not fil:
+ return
+
+ QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil))
+
+ if fil[-4:] == ".vtk":
+ self.project.export_holes_vtk(fil)
+ elif fil[-4:] == ".dxf":
+ self.project.export_holes_dxf(fil)
+ else:
+ self.__iface.messageBar().pushWarning("Albion", "unsupported extension for hole export")
+
+ def __export_layer(self):
+ assert(self.project)
+
+ table = None
+ for l in self.__iface.layerTreeView().selectedLayers():
+ uri = QgsDataSourceUri(l.dataProvider().dataSourceUri())
+ table = uri.table()
+ if table.endswith('_section'):
+ table = table[:-8]
+ break
+
+ if table is None:
+ self.__iface.messageBar().pushWarning("Albion", "you must select a layer")
+ return
+
+ fil, __ = QFileDialog.getSaveFileName(
+ None,
+ u"Export layer",
+ QgsProject.instance().readEntry("albion", "last_dir", "")[0],
+ "File formats (*.dxf *.vtk)",
+ )
+ if not fil:
+ return
+
+ QgsProject.instance().writeEntry("albion", "last_dir", os.path.dirname(fil))
+
+
+ if fil.endswith('.vtk'):
+ self.project.export_layer_vtk(table, fil)
+ elif fil.endswith('.dxf'):
+ self.project.export_layer_dxf(table, fil)
+ else:
+ self.__iface.messageBar().pushWarning("Albion", "unsupported extension for hole export")
+
def __import_project(self):
- fil = QFileDialog.getOpenFileName(
+ fil, __ = QFileDialog.getOpenFileName(
None,
u"Import project from file",
QgsProject.instance().readEntry("albion", "last_dir", "")[0],
@@ -683,13 +866,13 @@ def __import_project(self):
project = Project.import_(dbname, dump)
- QgsProject.instance().read(QFileInfo(prj))
+ QgsProject.instance().read(prj)
def __export_project(self):
if self.project is None:
return
- fil = QFileDialog.getSaveFileName(
+ fil, __ = QFileDialog.getSaveFileName(
None,
u"Export project",
QgsProject.instance().readEntry("albion", "last_dir", "")[0],
@@ -712,45 +895,37 @@ def __export_project(self):
os.path.split(QgsProject.instance().fileName())[1],
)
- def __create_section_view_0_90(self):
- if self.project is None:
- return
- self.project.create_section_view_0_90()
-
- def __log_strati_clicked(self):
- # @todo switch behavior when in section view -> ortho
- self.__click_tool = QgsMapToolEmitPoint(self.__iface.mapCanvas())
- self.__iface.mapCanvas().setMapTool(self.__click_tool)
- self.__click_tool.canvasClicked.connect(self.__map_log_clicked)
-
- def __map_log_clicked(self, point, button):
- self.__click_tool.setParent(None)
- self.__click_tool = None
-
- if self.project is None:
- self.__log_strati and self.__log_strati.setParent(None)
- self.__log_strati = None
- return
-
- if self.__log_strati is None:
- self.__log_strati = QDockWidget("Stratigraphic Log")
- self.__log_strati.setWidget(BoreHoleWindow(self.project))
- self.__iface.addDockWidget(Qt.LeftDockWidgetArea, self.__log_strati)
- self.__iface.mainWindow().tabifyDockWidget(
- self.__iface.mainWindow().findChild(QDockWidget, "Layers"),
- self.__log_strati,
- )
-
- res = self.project.closest_hole_id(point.x(), point.y())
- if res:
- self.__log_strati.widget().scene.set_current_id(res)
- self.__log_strati.show()
- self.__log_strati.raise_()
-
- def __section_from_selection(self):
- if self.project is None:
- return
-
+ #def __log_strati_clicked(self):
+ # # @todo switch behavior when in section view -> ortho
+ # self.__click_tool = QgsMapToolEmitPoint(self.__iface.mapCanvas())
+ # self.__iface.mapCanvas().setMapTool(self.__click_tool)
+ # self.__click_tool.canvasClicked.connect(self.__map_log_clicked)
+
+ #def __map_log_clicked(self, point, button):
+ # self.__click_tool.setParent(None)
+ # self.__click_tool = None
+
+ # if self.project is None:
+ # self.__log_strati and self.__log_strati.setParent(None)
+ # self.__log_strati = None
+ # return
+
+ # if self.__log_strati is None:
+ # self.__log_strati = QDockWidget("Stratigraphic Log")
+ # self.__log_strati.setWidget(BoreHoleWindow(self.project))
+ # self.__iface.addDockWidget(Qt.LeftDockWidgetArea, self.__log_strati)
+ # self.__iface.mainWindow().tabifyDockWidget(
+ # self.__iface.mainWindow().findChild(QDockWidget, "Layers"),
+ # self.__log_strati,
+ # )
+
+ # res = self.project.closest_hole_id(point.x(), point.y())
+ # if res:
+ # self.__log_strati.widget().scene.set_current_id(res)
+ # self.__log_strati.show()
+ # self.__log_strati.raise_()
+
+ def __line_from_selection(self):
if (
self.__iface.activeLayer()
and self.__iface.activeLayer().name() == u"collar"
@@ -783,9 +958,26 @@ def align(l):
align(numpy.array([f.geometry().asPoint() for f in selection]))
)
collar.removeSelection()
+ return line
+ else:
+ return None
+
+ def __add_section_from_selection(self):
+ assert(self.project)
+ line = self.__line_from_selection()
+ if line:
+ self.project.add_named_section(self.__current_section.currentText(), line)
+ self.__refresh_layers("named_section")
+
+
+ def __section_from_selection(self):
+ assert(self.project)
+ line = self.__line_from_selection()
+ if line:
self.project.set_section_geom(self.__current_section.currentText(), line)
self.__refresh_layers("section")
self.__viewer3d.widget().scene.update("section")
+ self.__viewer3d.widget().scene.update("volume_section")
self.__viewer3d.widget().update()
def open_help(self):
diff --git a/project.py b/project.py
index fefc065..6d390ac 100644
--- a/project.py
+++ b/project.py
@@ -1,11 +1,14 @@
# coding = utf-8
+from builtins import str
+from builtins import object
from pglite import cluster_params
import psycopg2
import os
import sys
import atexit
import binascii
+import string
from shapely import wkb
from dxfwrite import DXFEngine as dxf
@@ -23,16 +26,67 @@
from qgis.core import QgsMessageLog
+import time
+from psycopg2.extras import LoggingConnection, LoggingCursor
+import logging
+
+logging.basicConfig(level=logging.DEBUG)
+logger = logging.getLogger(__name__)
+# MyLoggingCursor simply sets self.timestamp at start of each query
+class MyLoggingCursor(LoggingCursor):
+ def execute(self, query, vars=None):
+ self.timestamp = time.time()
+ return super(MyLoggingCursor, self).execute(query, vars)
+
+ def callproc(self, procname, vars=None):
+ self.timestamp = time.time()
+ return super(MyLoggingCursor, self).callproc(procname, vars)
+
+# MyLogging Connection:
+# a) calls MyLoggingCursor rather than the default
+# b) adds resulting execution (+ transport) time via filter()
+class MyLoggingConnection(LoggingConnection):
+ def filter(self, msg, curs):
+ return "{} {} ms".format(msg, int((time.time() - curs.timestamp) * 1000))
+
+ def cursor(self, *args, **kwargs):
+ kwargs.setdefault('cursor_factory', MyLoggingCursor)
+ return LoggingConnection.cursor(self, *args, **kwargs)
+
+
if not check_cluster():
init_cluster()
start_cluster()
-# atexit.register(stop_cluster)
+
+#atexit.register(stop_cluster)
+TABLES = [
+ {'NAME': 'radiometry',
+ 'FIELDS_DEFINITION': 'gamma real',
+ },
+ {'NAME': 'resistivity',
+ 'FIELDS_DEFINITION': 'rho real',
+ },
+ {'NAME': 'formation',
+ 'FIELDS_DEFINITION': 'code integer, comments varchar',
+ },
+ {'NAME': 'lithology',
+ 'FIELDS_DEFINITION': 'code integer, comments varchar',
+ },
+ {'NAME': 'facies',
+ 'FIELDS_DEFINITION': 'code integer, comments varchar',
+ },
+ {'NAME': 'chemical',
+ 'FIELDS_DEFINITION': 'num_sample varchar, element varchar, thickness real, gt real, grade real, equi real, comments varchar',
+ },
+ {'NAME': 'mineralization',
+ 'FIELDS_DEFINITION': 'level_ real, oc real, accu real, grade real, comments varchar',
+ }]
def find_in_dir(dir_, name):
for filename in os.listdir(dir_):
if filename.find(name) != -1:
- return os.path.join(dir_, filename)
+ return os.path.abspath(os.path.join(dir_, filename))
return ""
@@ -69,14 +123,16 @@ def __init__(self, project_name):
self.__conn_info = "dbname={} {}".format(project_name, cluster_params())
def connect(self):
- return psycopg2.connect(self.__conn_info)
+ con = psycopg2.connect(self.__conn_info)#, connection_factory=MyLoggingConnection)
+ #con.initialize(logger)
+ return con
def vacuum(self):
with self.connect() as con:
- old_isolation_level = con.isolation_level
con.set_isolation_level(0)
cur = con.cursor()
cur.execute("vacuum analyze")
+ con.commit()
@staticmethod
def exists(project_name):
@@ -155,15 +211,79 @@ def create(project_name, srid):
)
)
con.commit()
+
+ for table in TABLES:
+ table['SRID'] = srid
+ project.add_table(table)
+
return project
+
+ def add_table(self, table, values=None, view_only=False):
+ """
+ table: a dict with keys
+ NAME: the name of the table to create
+ FIELDS_DEFINITION: the sql definition (name type) of the "additional" fields (i.e. excludes hole_id, from_ and to_)
+ SRID: the project's SRID
+ values: list of tuples (hole_id, from_, to_, ...)
+ """
+
+ fields = [f.split()[0].strip() for f in table['FIELDS_DEFINITION'].split(',')]
+ table['FIELDS'] = ', '.join(fields)
+ table['T_FIELDS'] = ', '.join(['t.{}'.format(f.replace(' ', '')) for f in fields])
+ table['FORMAT'] = ','.join([' %s' for v in fields])
+ table['NEW_FIELDS'] = ','.join(['new.{}'.format(v) for v in fields])
+ table['SET_FIELDS'] = ','.join(['{}=new.{}'.format(v,v) for v in fields])
+ with self.connect() as con:
+ cur = con.cursor()
+ for file_ in (("albion_table.sql",) if view_only else ("_albion_table.sql", "albion_table.sql")):
+ for statement in (
+ open(os.path.join(os.path.dirname(__file__), file_))
+ .read()
+ .split("\n;\n")[:-1]
+ ):
+ cur.execute(
+ string.Template(statement).substitute(table)
+ )
+ if values is not None:
+ cur.executemany("""
+ insert into albion.{NAME}(hole_id, from_, to_, {FIELDS})
+ values (%s, %s, %s, {FORMAT})
+ """.format(**table), values)
+ cur.execute("""
+ refresh materialized view albion.{NAME}_section_geom_cache
+ """.format(**table))
+ con.commit()
+ self.vacuum()
+
+
def update(self):
"reload schema albion without changing data"
+
with self.connect() as con:
cur = con.cursor()
cur.execute("select srid from albion.metadata")
srid, = cur.fetchone()
cur.execute("drop schema if exists albion cascade")
+
+ # test if version number is in metadata
+ cur.execute("""
+ select column_name
+ from information_schema.columns where table_name = 'metadata'
+ and column_name='version'
+ """);
+ if cur.fetchone():
+ # here goes future upgrades
+ cur.execute("select version from _albion.metadata")
+ else:
+ # old albion version, we upgrade the data
+ for statement in (
+ open(os.path.join(os.path.dirname(__file__), "_albion_v1_to_v2.sql"))
+ .read()
+ .split("\n;\n")[:-1]
+ ):
+ cur.execute(statement.replace("$SRID", str(srid)))
+
include_elementary_volume = open(
os.path.join(
os.path.dirname(__file__), "elementary_volume", "__init__.py"
@@ -179,23 +299,99 @@ def update(self):
"$INCLUDE_ELEMENTARY_VOLUME", include_elementary_volume
)
)
+
con.commit()
+ cur.execute("select name, fields_definition from albion.layer")
+ tables = [{'NAME': r[0], 'FIELDS_DEFINITION': r[1]} for r in cur.fetchall()]
+
+ for table in tables:
+ table['SRID'] = str(srid)
+ self.add_table(table, view_only=True)
+
+ self.vacuum()
+
+ def export_sections_obj(self, graph, filename):
+
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ with hole_idx as (
+ select s.id as section_id, h.id as hole_id
+ from _albion.named_section as s
+ join _albion.hole as h on s.geom && h.geom and st_intersects(s.geom, st_startpoint(h.geom))
+ )
+ select albion.to_obj(st_collectionhomogenize(st_collect(ef.geom)))
+ from albion.all_edge as e
+ join hole_idx as hs on hs.hole_id = e.start_
+ join hole_idx as he on he.hole_id = e.end_ and he.section_id = hs.section_id
+ join albion.edge_face as ef on ef.start_ = e.start_ and ef.end_ = e.end_ and not st_isempty(ef.geom)
+ where ef.graph_id='{}'
+ """.format(
+ graph
+ )
+ )
+ open(filename, "w").write(cur.fetchone()[0])
+
+ def export_sections_dxf(self, graph, filename):
+
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ with hole_idx as (
+ select s.id as section_id, h.id as hole_id
+ from _albion.named_section as s
+ join _albion.hole as h on s.geom && h.geom and st_intersects(s.geom, st_startpoint(h.geom))
+ )
+ select st_collectionhomogenize(st_collect(ef.geom))
+ from albion.all_edge as e
+ join hole_idx as hs on hs.hole_id = e.start_
+ join hole_idx as he on he.hole_id = e.end_ and he.section_id = hs.section_id
+ join albion.edge_face as ef on ef.start_ = e.start_ and ef.end_ = e.end_ and not st_isempty(ef.geom)
+ where ef.graph_id='{}'
+ """.format(
+ graph
+ )
+ )
+
+ drawing = dxf.drawing(filename)
+ m = wkb.loads(bytes.fromhex(cur.fetchone()[0]))
+ for p in m:
+ r = p.exterior.coords
+ drawing.add(
+ dxf.face3d([tuple(r[0]), tuple(r[1]), tuple(r[2])], flags=1)
+ )
+ drawing.save()
+
+
+ def __srid(self):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute("select srid from albion.metadata")
+ srid, = cur.fetchone()
+ return srid
+
def __getattr__(self, name):
- if name == "has_collar":
- return self.__has_collar()
- elif name == "has_hole":
+ if name == "has_hole":
return self.__has_hole()
elif name == "has_section":
return self.__has_section()
+ elif name == "has_volume":
+ return self.__has_volume()
elif name == "has_group_cell":
return self.__has_group_cell()
+ elif name == "has_graph":
+ return self.__has_graph()
elif name == "has_radiometry":
return self.__has_radiometry()
elif name == "has_cell":
return self.__has_cell()
elif name == "name":
return self.__name
+ elif name == "srid":
+ return self.__srid()
else:
raise AttributeError(name)
@@ -203,46 +399,56 @@ def __has_cell(self):
with self.connect() as con:
cur = con.cursor()
cur.execute("select count(1) from albion.cell")
- return cur.fetchone()[0] > 1
+ return cur.fetchone()[0] > 0
- def __has_collar(self):
+ def __has_hole(self):
with self.connect() as con:
cur = con.cursor()
- cur.execute("select count(1) from albion.collar")
- return cur.fetchone()[0] > 1
+ cur.execute("select count(1) from albion.hole where geom is not null")
+ return cur.fetchone()[0] > 0
- def __has_hole(self):
+ def __has_volume(self):
with self.connect() as con:
cur = con.cursor()
- cur.execute("select count(1) from albion.hole")
- return cur.fetchone()[0] > 1
+ cur.execute("select count(1) from albion.volume")
+ return cur.fetchone()[0] > 0
def __has_section(self):
with self.connect() as con:
cur = con.cursor()
- cur.execute("select count(1) from albion.section_geom")
- return cur.fetchone()[0] > 1
+ cur.execute("select count(1) from albion.named_section")
+ return cur.fetchone()[0] > 0
def __has_group_cell(self):
with self.connect() as con:
cur = con.cursor()
cur.execute("select count(1) from albion.group_cell")
- return cur.fetchone()[0] > 1
+ return cur.fetchone()[0] > 0
+
+ def __has_graph(self):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute("select count(1) from albion.graph")
+ return cur.fetchone()[0] > 0
def __has_radiometry(self):
with self.connect() as con:
cur = con.cursor()
cur.execute("select count(1) from albion.radiometry")
- return cur.fetchone()[0] > 1
+ return cur.fetchone()[0] > 0
+
+
def import_data(self, dir_, progress=None):
+
progress = progress if progress is not None else DummyProgress()
with self.connect() as con:
cur = con.cursor()
+
cur.execute(
"""
- copy _albion.collar(id, x, y, z, date_, comments) from '{}' delimiter ';' csv header
+ copy _albion.hole(id, x, y, z, depth_, date_, comments) from '{}' delimiter ';' csv header
""".format(
find_in_dir(dir_, "collar")
)
@@ -252,29 +458,23 @@ def import_data(self, dir_, progress=None):
cur.execute(
"""
- update _albion.collar set geom=format('SRID=%s;POINTZ(%s %s %s)',m. srid, x, y, z)::geometry
- from albion.metadata as m
- """
- )
-
- cur.execute(
- """
- insert into _albion.hole(id, collar_id) select id, id from _albion.collar;
- """
+ copy _albion.deviation(hole_id, from_, dip, azimuth) from '{}' delimiter ';' csv header
+ """.format(
+ find_in_dir(dir_, "devia")
+ )
)
progress.setPercent(10)
cur.execute(
"""
- copy _albion.deviation(hole_id, from_, dip, azimuth) from '{}' delimiter ';' csv header
- """.format(
- find_in_dir(dir_, "devia")
- )
+ update _albion.hole set geom = albion.hole_geom(id)
+ """
)
progress.setPercent(15)
+
if find_in_dir(dir_, "avp"):
cur.execute(
"""
@@ -330,91 +530,20 @@ def import_data(self, dir_, progress=None):
progress.setPercent(40)
- cur.execute(
- """
- with dep as (
- select hole_id, max(to_) as mx
- from (
- select hole_id, max(to_) as to_ from _albion.radiometry group by hole_id
- union all
- select hole_id, max(to_) as to_ from _albion.resistivity group by hole_id
- union all
- select hole_id, max(to_) as to_ from _albion.formation group by hole_id
- union all
- select hole_id, max(to_) as to_ from _albion.lithology group by hole_id
- union all
- select hole_id, max(to_) as to_ from _albion.facies group by hole_id
- union all
- select hole_id, max(from_) as to_ from _albion.deviation group by hole_id
- ) as t
- group by hole_id
- )
- update _albion.hole as h set depth_=d.mx
- from dep as d where h.id=d.hole_id
- """
- )
-
- progress.setPercent(50)
-
- cur.execute("update albion.hole set geom=albion.hole_geom(id)")
-
- progress.setPercent(55)
-
- cur.execute(
- "update albion.lithology set geom=albion.hole_piece(from_, to_, hole_id)"
- )
-
- progress.setPercent(60)
-
- cur.execute(
- "update albion.formation set geom=albion.hole_piece(from_, to_, hole_id)"
- )
-
- progress.setPercent(65)
-
- cur.execute(
- "update albion.radiometry set geom=albion.hole_piece(from_, to_, hole_id)"
- )
-
- progress.setPercent(70)
-
- cur.execute(
- "update albion.resistivity set geom=albion.hole_piece(from_, to_, hole_id)"
- )
-
- progress.setPercent(75)
-
- cur.execute(
- "update albion.facies set geom=albion.hole_piece(from_, to_, hole_id)"
- )
-
- if find_in_dir(dir_, "mineralization"):
- cur.execute(
- """
- copy _albion.mineralization(hole_id, level_, from_, to_, oc, accu, grade) from '{}' delimiter ';' csv header
- """.format(
- find_in_dir(dir_, "mineralization")
- )
- )
-
- cur.execute(
- "update albion.mineralization set geom=albion.hole_piece(from_, to_, hole_id)"
- )
-
- progress.setPercent(80)
-
if find_in_dir(dir_, "chemical"):
cur.execute(
"""
copy _albion.chemical(hole_id, from_, to_, num_sample,
- element, thickness, gt, grade, equi, comments
- )
+ element, thickness, gt, grade, equi, comments)
from '{}' delimiter ';' csv header
""".format(
find_in_dir(dir_, "chemical")
)
)
+ progress.setPercent(45)
+
+
progress.setPercent(100)
con.commit()
@@ -427,24 +556,6 @@ def triangulate(self):
cur.execute("select albion.triangulate()")
con.commit()
- def refresh_all_edge(self):
- with self.connect() as con:
- cur = con.cursor()
- cur.execute("refresh materialized view albion.all_edge")
- con.commit()
-
- def refresh_radiometry(self):
- with self.connect() as con:
- cur = con.cursor()
- cur.execute("refresh materialized view albion.radiometry_section")
- con.commit()
-
- def refresh_resistivity(self):
- with self.connect() as con:
- cur = con.cursor()
- cur.execute("refresh materialized view albion.resistivity_section")
- con.commit()
-
def create_sections(self):
with self.connect() as con:
cur = con.cursor()
@@ -474,7 +585,7 @@ def new_graph(self, graph, parent=None):
cur.execute("insert into albion.graph(id) values ('{}');".format(graph))
con.commit()
- def delete_graph(self):
+ def delete_graph(self, graph):
with self.connect() as con:
cur = con.cursor()
cur.execute("delete from albion.graph cascade where id='{}';".format(graph))
@@ -486,38 +597,8 @@ def previous_section(self, section):
cur = con.cursor()
cur.execute(
"""
- select group_id from albion.section where id='{}'
- """.format(
- section
- )
- )
- group, = cur.fetchone()
- group = group or 0
- cur.execute(
- """
- select group_id, geom from albion.section_geom
- where section_id='{section}'
- and group_id < {group}
- order by group_id desc
- limit 1
- """.format(
- group=group, section=section
- )
- )
- res = cur.fetchone()
- if res:
- sql = """
- update albion.section set group_id={}, geom='{}'::geometry where id='{}'
- """.format(
- res[0], res[1], section
- )
- else:
- sql = """
- update albion.section set group_id=null, geom=albion.first_section(anchor) where id='{}'
- """.format(
- section
- )
- cur.execute(sql)
+ update albion.section set geom=coalesce(albion.previous_section(%s), geom) where id=%s
+ """, (section, section))
con.commit()
def next_section(self, section):
@@ -527,53 +608,99 @@ def next_section(self, section):
cur = con.cursor()
cur.execute(
"""
- select group_id from albion.section where id='{}'
- """.format(
- section
- )
- )
- group, = cur.fetchone()
- group = group or 0
+ update albion.section set geom=coalesce(albion.next_section(%s), geom) where id=%s
+ """, (section, section))
+ con.commit()
+
+ def next_subsection(self, section):
+ with self.connect() as con:
+ print("select section from distance")
+ cur = con.cursor()
cur.execute(
"""
- select group_id, geom from albion.section_geom
+ select sg.group_id
+ from albion.section_geom sg
+ join albion.section s on s.id=sg.section_id
+ where s.id='{section}'
+ order by st_distance(s.geom, sg.geom), st_HausdorffDistance(s.geom, sg.geom) asc
+ limit 1
+ """.format(section=section))
+ res = cur.fetchone()
+ if not res:
+ return
+ group = res[0] or 0
+ print("select geom for next")
+ cur.execute(
+ """
+ select geom from albion.section_geom
where section_id='{section}'
and group_id > {group}
order by group_id asc
- limit 1
- """.format(
- group=group, section=section
- )
+ limit 1 """.format( group=group, section=section)
)
res = cur.fetchone()
+ print("update section")
if res:
sql = """
- update albion.section set group_id={}, geom='{}'::geometry where id='{}'
- """.format(
- res[0], res[1], section
- )
+ update albion.section set geom=st_multi('{}'::geometry) where id='{}'
+ """.format(res[0], section)
cur.execute(sql)
con.commit()
+ print("done")
- def next_group_ids(self):
+ def previous_subsection(self, section):
with self.connect() as con:
cur = con.cursor()
cur.execute(
"""
- select cell_id from albion.next_group where section_id='{}'
- """.format(
- self.__current_section.currentText()
- )
- )
- return [cell_id for cell_id, in cur.fetchall()]
+ select sg.group_id
+ from albion.section_geom sg
+ join albion.section s on s.id=sg.section_id
+ where s.id='{section}'
+ order by st_distance(s.geom, sg.geom), st_HausdorffDistance(s.geom, sg.geom) asc
+ limit 1
+ """.format(section=section))
+ res = cur.fetchone()
+ if not res:
+ return
+ group = res[0] or 0
+ cur.execute(
+ """
+ select geom from albion.section_geom
+ where section_id='{section}'
+ and group_id < {group}
+ order by group_id desc
+ limit 1
+ """.format(group=group, section=section))
+ res = cur.fetchone()
+ if res:
+ sql = """
+ update albion.section set geom=st_multi('{}'::geometry) where id='{}'
+ """.format(res[0], section)
+ cur.execute(sql)
+ con.commit()
+
+
+# def next_group_ids(self):
+# with self.connect() as con:
+# cur = con.cursor()
+# cur.execute(
+# """
+# select cell_id from albion.next_group where section_id='{}'
+# """.format(
+# self.__current_section.currentText()
+# )
+# )
+# return [cell_id for cell_id, in cur.fetchall()]
+#
def create_group(self, section, ids):
with self.connect() as con:
# add group
cur = con.cursor()
cur.execute(
"""
- insert into albion.group default values returning id
+ insert into albion.group(id) values ((select coalesce(max(id)+1, 1) from albion.group)) returning id
"""
)
group, = cur.fetchone()
@@ -618,13 +745,9 @@ def compute_mineralization(self, cutoff, ci, oc):
oc=oc, ci=ci, cutoff=cutoff
)
)
- cur.execute(
- """
- update albion.mineralization set geom=albion.hole_piece(from_, to_, hole_id)
- where geom is null
- """
- )
+ cur.execute("refresh materialized view albion.mineralization_section_geom_cache")
con.commit()
+
def export_obj(self, graph_id, filename):
with self.connect() as con:
@@ -642,60 +765,50 @@ def export_obj(self, graph_id, filename):
)
open(filename, "w").write(cur.fetchone()[0])
- def export_elementary_volume_obj(self, graph_id, cell_id, outdir, closed):
+ def export_elementary_volume_obj(self, graph_id, cell_ids, outdir, closed_only=False):
with self.connect() as con:
- closed_sql = ""
- if not closed:
- closed_sql = "not"
-
cur = con.cursor()
cur.execute(
"""
- select albion.to_obj(geom) from albion.dynamic_volume
- where cell_id='{}' and graph_id='{}'
- and {} albion.is_closed_volume(geom)
+ select cell_id, row_number() over(partition by cell_id order by closed desc), obj, closed
+ from (
+ select cell_id, albion.to_obj(triangulation) as obj, albion.is_closed_volume(triangulation) as closed
+ from albion.volume
+ where cell_id in ({}) and graph_id='{}'
+ ) as t
""".format(
- cell_id, graph_id, closed_sql
+ ','.join(["'{}'".format(c) for c in cell_ids]), graph_id
)
)
-
- status = "opened"
- if closed:
- status = "closed"
-
- i = 0
- for obj in cur.fetchall():
- filename = '{}_{}_{}_{}.obj'.format(cell_id, graph_id, status, i)
- i += 1
+ for cell_id, i, obj, closed in cur.fetchall():
+ if closed_only and not closed:
+ continue
+ filename = '{}_{}_{}_{}.obj'.format(cell_id, graph_id, "closed" if closed else "opened", i)
path = os.path.join(outdir, filename)
open(path, "w").write(obj[0])
+
- def export_elementary_volume_dxf(self, graph_id, cell_id, outdir, closed):
+ def export_elementary_volume_dxf(self, graph_id, cell_ids, outdir, closed_only=False):
with self.connect() as con:
- closed_sql = ""
- if not closed:
- closed_sql = "not"
-
cur = con.cursor()
cur.execute(
"""
- select geom from albion.dynamic_volume
- where cell_id='{}' and graph_id='{}'
- and {} albion.is_closed_volume(geom)
+ select cell_id, row_number() over(partition by cell_id order by closed desc), geom, closed
+ from (
+ select cell_id, triangulation as geom, albion.is_closed_volume(triangulation) as closed
+ from albion.volume
+ where cell_id in ({}) and graph_id='{}'
+ ) as t
""".format(
- cell_id, graph_id, closed_sql
+ ','.join(["'{}'".format(c) for c in cell_ids]), graph_id
)
)
- status = "opened"
- if closed:
- status = "closed"
-
- i = 0
- for wkb_geom in cur.fetchall():
- geom = wkb.loads(bytes.fromhex(wkb_geom[0]))
-
- filename = '{}_{}_{}_{}.dxf'.format(cell_id, graph_id, status, i)
+ for cell_id, i, wkb_geom, closed in cur.fetchall():
+ geom = wkb.loads(bytes.fromhex(wkb_geom))
+ if closed_only and not closed:
+ continue
+ filename = '{}_{}_{}_{}.dxf'.format(cell_id, graph_id, "closed" if closed else "opened", i)
path = os.path.join(outdir, filename)
drawing = dxf.drawing(path)
@@ -706,8 +819,6 @@ def export_elementary_volume_dxf(self, graph_id, cell_id, outdir, closed):
)
drawing.save()
- i += 1
-
def errors_obj(self, graph_id, filename):
with self.connect() as con:
cur = con.cursor()
@@ -747,6 +858,64 @@ def export_dxf(self, graph_id, filename):
)
drawing.save()
+ def export_holes_vtk(self, filename):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ select albion.to_vtk(st_collect(geom))
+ from albion.hole
+ """
+ )
+ open(filename, "w").write(cur.fetchone()[0])
+
+ def export_holes_dxf(self, filename):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ select st_collect(geom)
+ from albion.hole
+ """
+ )
+ drawing = dxf.drawing(filename)
+ m = wkb.loads(bytes.fromhex(cur.fetchone()[0]))
+ for l in m:
+ r = l.coords
+ drawing.add(
+ dxf.polyline(list(l.coords))
+ )
+ drawing.save()
+
+ def export_layer_vtk(self, table, filename):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ select albion.to_vtk(st_collect(albion.hole_piece(from_, to_, hole_id)))
+ from albion.{}
+ """.format(table)
+ )
+ open(filename, "w").write(cur.fetchone()[0])
+
+ def export_layer_dxf(self, table, filename):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ select st_collect(albion.hole_piece(from_, to_, hole_id))
+ from albion.{}
+ """.format(table)
+ )
+ drawing = dxf.drawing(filename)
+ m = wkb.loads(bytes.fromhex(cur.fetchone()[0]))
+ for l in m:
+ r = l.coords
+ drawing.add(
+ dxf.polyline(list(l.coords))
+ )
+ drawing.save()
+
def create_volumes(self, graph_id):
with self.connect() as con:
cur = con.cursor()
@@ -759,8 +928,8 @@ def create_volumes(self, graph_id):
)
cur.execute(
"""
- insert into albion.volume(graph_id, cell_id, triangulation)
- select graph_id, cell_id, geom
+ insert into _albion.volume(graph_id, cell_id, triangulation, face1, face2, face3)
+ select graph_id, cell_id, geom, face1, face2, face3
from albion.dynamic_volume
where graph_id='{}'
and geom is not null --not st_isempty(geom)
@@ -782,8 +951,8 @@ def create_terminations(self, graph_id):
)
cur.execute(
"""
- insert into albion.end_node(geom, node_id, collar_id, graph_id)
- select geom, node_id, collar_id, graph_id
+ insert into albion.end_node(geom, node_id, hole_id, graph_id)
+ select geom, node_id, hole_id, graph_id
from albion.dynamic_end_node
where graph_id='{}'
""".format(
@@ -799,6 +968,7 @@ def export(self, filename):
def import_(name, filename):
import_db(filename, name)
project = Project(name)
+ project.update()
project.create_sections()
return project
@@ -851,10 +1021,18 @@ def create_section_view_0_90(self, z_scale):
)
)
- cur.execute("refresh materialized view albion.radiometry_section")
- cur.execute("refresh materialized view albion.resistivity_section")
+ #cur.execute("refresh materialized view albion.radiometry_section")
+ #cur.execute("refresh materialized view albion.resistivity_section")
con.commit()
+ def refresh_section_geom(self, table):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute("select count(1) from albion.layer where name='{}'".format(table))
+ if cur.fetchone()[0]:
+ cur.execute("refresh materialized view albion.{}_section_geom_cache".format(table))
+ con.commit()
+
def closest_hole_id(self, x, y):
with self.connect() as con:
cur = con.cursor()
@@ -873,7 +1051,7 @@ def closest_hole_id(self, x, y):
if not res:
cur.execute(
"""
- select hole_id from albion.current_hole_section
+ select hole_id from albion.hole_section
where st_dwithin(geom, 'SRID={srid} ;POINT({x} {y})'::geometry, 25)
order by st_distance('SRID={srid} ;POINT({x} {y})'::geometry, geom)
limit 1""".format(
@@ -884,6 +1062,21 @@ def closest_hole_id(self, x, y):
return res[0] if res else None
+ def add_named_section(self, section_id, geom):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute("select srid from albion.metadata")
+ srid, = cur.fetchone()
+ cur.execute(
+ """
+ insert into albion.named_section(geom, section)
+ values (ST_SetSRID('{wkb_hex}'::geometry, {srid}), '{section_id}')
+ """.format(
+ srid=srid, wkb_hex=geom.wkb_hex, section_id=section_id
+ )
+ )
+ con.commit()
+
def set_section_geom(self, section_id, geom):
with self.connect() as con:
cur = con.cursor()
@@ -891,9 +1084,31 @@ def set_section_geom(self, section_id, geom):
srid, = cur.fetchone()
cur.execute(
"""
- update albion.section set geom=ST_SetSRID('{wkb_hex}'::geometry, {srid}) where id='{id_}'
+ update albion.section set geom=st_multi(ST_SetSRID('{wkb_hex}'::geometry, {srid})) where id='{id_}'
""".format(
- srid=srid, wkb_hex=binascii.hexlify(geom.wkb), id_=section_id
+ srid=srid, wkb_hex=geom.wkb_hex, id_=section_id
)
)
con.commit()
+
+ def add_to_graph_node(self, graph, features):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.executemany(
+ """
+ insert into albion.node(from_, to_, hole_id, graph_id) values(%s, %s, %s, %s)
+ """,
+ [(f['from_'], f['to_'], f['hole_id'], graph) for f in features])
+
+ def accept_possible_edge(self, graph):
+ with self.connect() as con:
+ cur = con.cursor()
+ cur.execute(
+ """
+ insert into albion.edge(start_, end_, graph_id, geom)
+ select start_, end_, graph_id, geom from albion.possible_edge
+ where graph_id=%s
+ """,
+ (graph,))
+
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..b2b297e
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,7 @@
+gitpython
+dxfwrite
+PyOpenGL
+pglite
+pyqt5
+psycopg2
+shapely
diff --git a/res/next_line_big.svg b/res/next_line_big.svg
new file mode 100644
index 0000000..fe34c3c
--- /dev/null
+++ b/res/next_line_big.svg
@@ -0,0 +1,81 @@
+
+
+
+
diff --git a/res/previous_line_big.svg b/res/previous_line_big.svg
new file mode 100644
index 0000000..dba587c
--- /dev/null
+++ b/res/previous_line_big.svg
@@ -0,0 +1,81 @@
+
+
+
+
diff --git a/res/template_project.qgs b/res/template_project.qgs
index 9a82be1..c394e96 100644
--- a/res/template_project.qgs
+++ b/res/template_project.qgs
@@ -1,67 +1,166 @@
-
+
+
-
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ - cell_99e875c2_110e_4f52_a7f4_54ea9cff1367
+ - collar_7e814841_4cc9_495a_8ef6_9229fcfffb5e
+ - edge_32c6a82a_82cd_477f_b119_398536a6b6ed
+ - edge_section_8b745326_1406_43a8_803e_8ee85be59103
+ - end_node_section_node_geom_f653243c_2e98_4638_b428_1acca01868dc
+ - group_cell_ec51a010_ab41_49d7_ac55_8ce0cfbb8838
+ - hole_section_1f8c7d9f_7032_4a97_8033_d7ee1c22ea2a
+ - node_section_63e3816d_ea42_44c6_937c_65c10a3b3ac4
+ - possible_edge_a6b83b46_56da_4098_b0fe_e703633800f5
+ - possible_edge_section_04705590_fcdc_4fe9_8309_3d2c648db28f
+ - section_anchor_5a49e7a1_cea4_4a35_982c_00e7801cd6da
+ - section_intersection_13a1d3a9_897b_48fc_9714_e20439ad1ff6
+ - section_polygon_f49e48f4_9101_4351_a07c_0a99748eaca2
+ - close_collar_95b0fcfd_f8c9_476f_9b9d_39d3d8c782f7
+ - section_geom_cbc425ee_c515_4cda_8fec_53f986b4dc2f
+ - named_section_geom_d56ae49a_c71c_485f_84ea_2a788ff48e0b
+ - mineralization_ed8c17ee_2398_4fc0_8deb_6db49e2465d7
+ - radiometry_9d3b823d_d1b6_47a8_a1c2_dd0895a7262e
+ - resistivity_4ed802a8_e512_490c_bf34_cd284ac03506
+ - facies_047eef51_ef17_438a_b299_7879992c4e6a
+ - formation_8aad2fae_f596_4e4a_b6c4_dea6ae893731
+ - mineralization_b5620aba_20dd_42f3_8de8_271f443b4578
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
meters
- 322700.65761908068088815
- 2074283.03263000538572669
- 324598.16511556104524061
- 2075541.11146176373586059
+ 31738932.63210045173764229
+ 33490672.35866895318031311
+ 31739689.99440045282244682
+ 33491176.27513902634382248
0
- 1
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -75,258 +174,139 @@
0
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- - collar20170522101211588
- - metadata20170602185222421
- - current_radiometry_section20171210141136639
- - current_mineralization_section20171210141434594
- - group_cell20171210141649354
- - section_geom20171210141834658
- - cell20171210155444151
- - current_hole_section20171210181943739
- - current_formation_section20171210182253618
- - current_node_section20171211135743640
- - current_edge_section20171211173954570
- - edge20171211174003737
- - Google_cn_Satellites20171215210416430
- - possible_edge20171219072744468
- - section_anchor20171220085838796
-
-
+
+
-
-
- -20037508.34278924390673637
- -20037508.34278924390673637
- 20037508.34278924390673637
- 20037508.34278924390673637
-
- Google_cn_Satellites20171215210416430
- .
-
-
-
- Google.cn Satellites
-
-
- +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs
- 3857
- 3857
- EPSG:3857
- WGS 84 / Pseudo Mercator
- merc
- WGS84
- false
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 323136.61999999999534339
- 2074866.80000000004656613
- 323587.19000000000232831
- 2075166.59000000008381903
-
- cell20171210155444151
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=Polygon table="albion"."cell" (geom) sql=
+
+ cell_99e875c2_110e_4f52_a7f4_54ea9cff1367
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=Polygon checkPrimaryKeyUnicity='1' table="albion"."cell" (geom) sql=
@@ -343,313 +323,179 @@
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
-
+
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
+
-
-
- 323136.61999999999534339
- 2074866.80000000004656613
- 323587.19000000000232831
- 2075166.59000000008381903
-
- collar20170522101211588
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=PointZ table="albion"."collar" (geom) sql=
+
+ close_collar_95b0fcfd_f8c9_476f_9b9d_39d3d8c782f7
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."close_collar" (geom) sql=
- collar
+ close_collar
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -662,271 +508,165 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 1
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
- COALESCE( "id", '<NULL>' )
+ id
+
-
+
- 323137.12120096100261435
- 2074749.36095459992066026
- 323737.77071975398575887
- 2075166.65021662996150553
+ 31739063.62000000104308128
+ 33490793.80000000074505806
+ 31739514.19000000134110451
+ 33491093.58999999985098839
- current_edge_section20171211173954570
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."current_edge_section" (geom) sql=
+ collar_7e814841_4cc9_495a_8ef6_9229fcfffb5e
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."collar" (geom) sql=
- current_edge_section
+ collar
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -982,386 +720,243 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 1
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
- COALESCE( "id", '<NULL>' )
+ id
+
-
- current_formation_section20171210182253618
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."current_formation_section" (geom) sql=
+
+ edge_32c6a82a_82cd_477f_b119_398536a6b6ed
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineStringZ checkPrimaryKeyUnicity='1' table="albion"."edge" (geom) sql=
- current_formation_section
+ edge
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -1374,487 +969,173 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
-
+
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
- current_hole_section20171210181943739
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."current_hole_section" (geom) sql=
+
+ edge_section_8b745326_1406_43a8_803e_8ee85be59103
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."edge_section" (geom) sql=
- current_hole_section
+ edge_section
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -1867,130 +1148,2007 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+
+
+
+ end_node_section_node_geom_f653243c_2e98_4638_b428_1acca01868dc
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."end_node_section" (node_geom) sql=
+
+
+
+ end_node_section.node_geom
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ id
+
+
+
+ facies_047eef51_ef17_438a_b299_7879992c4e6a
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."facies" (geom) sql=
+
+
+
+ facies
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+
+ 31739063.62000000104308128
+ 33490793.80000000074505806
+ 31739514.19000000134110451
+ 33491093.58999999985098839
+
+ formation_8aad2fae_f596_4e4a_b6c4_dea6ae893731
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."formation" (geom) sql=
+
+
+
+ formation
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+ group_cell_ec51a010_ab41_49d7_ac55_8ce0cfbb8838
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='id' srid=32632 type=Polygon checkPrimaryKeyUnicity='1' table="albion"."group_cell" (geom) sql=section_id='SN x4'
+
+
+
+ group_cell
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+ hole_section_1f8c7d9f_7032_4a97_8033_d7ee1c22ea2a
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."hole_section" (geom) sql=
+
+
+
+ hole_section
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+ metadata_c78c898c_772f_4524_8e45_76de4e0463d3
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' checkPrimaryKeyUnicity='1' table="albion"."metadata" sql=
+
+
+
+ metadata
+
+
+
+ 0
+ 0
+
+
+
+
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+
+ 31739088.89999999850988388
+ 33490793.80000000074505806
+ 31739505.76999999955296516
+ 33491092.85000000149011612
+
+ mineralization_b5620aba_20dd_42f3_8de8_271f443b4578
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."mineralization" (geom) sql=
+
+
+
+ mineralization
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
+
+
+ mineralization_ed8c17ee_2398_4fc0_8deb_6db49e2465d7
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."mineralization" (geom) sql=
+
+
+
+ mineralization
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- 323288.30356994899921119
- 2074730.4480744400061667
- 323738.71807432197965682
- 2075067.08355449000373483
-
- current_mineralization_section20171210141434594
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."current_mineralization_section" (geom) sql=
+
+ named_section_geom_d56ae49a_c71c_485f_84ea_2a788ff48e0b
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."named_section" (geom) sql=
- current_mineralization_section
+ named_section.geom
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -2003,405 +3161,329 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
- 1
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 0
+ 1
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ id
+
-
-
- 323137.3236906590173021
- 2074746.90201969002373517
- 323741.30310256197117269
- 2075166.57410508999601007
-
- current_node_section20171211135743640
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."current_node_section" (geom) sql=
+
+ node_section_63e3816d_ea42_44c6_937c_65c10a3b3ac4
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."node_section" (geom) sql=
- current_node_section
+ node_section
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -2414,399 +3496,294 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
- 4
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 0
+ 1
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
- COALESCE( "id", '<NULL>' )
+ id
+
-
-
- 323136.99737213598564267
- 2074730.70236835000105202
- 323784.47420165798394009
- 2075092.06782471993938088
-
- current_radiometry_section20171210141136639
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."current_radiometry_section" (geom) sql=
+
+ possible_edge_a6b83b46_56da_4098_b0fe_e703633800f5
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineStringZ checkPrimaryKeyUnicity='1' table="albion"."possible_edge" (geom) sql=
- current_radiometry_section
+ possible_edge
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -2819,327 +3796,173 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
-
+
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
-
+
-
-
- 323136.50877837499137968
- 2074866.45427859993651509
- 323588.2962775370106101
- 2075165.99685759004205465
-
- edge20171211174003737
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineStringZ table="albion"."edge" (geom) sql=
+
+ possible_edge_section_04705590_fcdc_4fe9_8309_3d2c648db28f
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."possible_edge_section" (geom) sql=
- edge
+ possible_edge_section
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -3152,381 +3975,388 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
-
+
+
0
generatedlayout
+
+
+
+
+
+
+
+ 31739063.62000000104308128
+ 33490793.80000000074505806
+ 31739514.19000000134110451
+ 33491093.58999999985098839
+
+ radiometry_9d3b823d_d1b6_47a8_a1c2_dd0895a7262e
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."radiometry" (geom) sql=
+
+
+
+ radiometry
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+ postgres
+
+
+
+
+
+
+
+
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
- COALESCE( "id", '<NULL>' )
+
+
+ 0
+
+
+ 0
+ generatedlayout
+
+
+
+
+
-
+
- 323136.61999999999534339
- 2074866.80000000004656613
- 323587.19000000000232831
- 2075166.59000000008381903
+ 31739063.62000000104308128
+ 33490793.80000000074505806
+ 31739514.19000000134110451
+ 33491093.58999999985098839
- group_cell20171210141649354
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=Polygon table="albion"."group_cell" (geom) sql=section_id='WE'
+ resistivity_4ed802a8_e512_490c_bf34_cd284ac03506
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=PointZ checkPrimaryKeyUnicity='1' table="albion"."resistivity" (geom) sql=
- group_cell
+ resistivity
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -3539,475 +4369,360 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
-
+
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
- COALESCE( "id", '<NULL>' )
+
+
-
- metadata20170602185222421
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' table="albion"."metadata" sql=
+
+
+ 31739063.30036709830164909
+ 33490657.7391928993165493
+ 31739651.99177160114049911
+ 33491093.58999999985098839
+
+ section_anchor_5a49e7a1_cea4_4a35_982c_00e7801cd6da
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=LineString checkPrimaryKeyUnicity='1' table="albion"."section" (anchor) sql=
- metadata
+ section.anchor
- +proj=longlat +datum=WGS84 +no_defs
- 3452
- 4326
- EPSG:4326
- WGS 84
- longlat
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
WGS84
- true
+ false
-
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+
+
+ 1
+ 1
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- COALESCE("id", '<NULL>')
+
+
-
- possible_edge20171219072744468
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineStringZ table="albion"."possible_edge" (geom) sql=
+
+ section_geom_cbc425ee_c515_4cda_8fec_53f986b4dc2f
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=MultiLineString checkPrimaryKeyUnicity='1' table="albion"."section" (geom) sql=
- possible_edge
+ section.geom
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -4020,381 +4735,318 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 1
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
- .
+
+
+
+
+
0
- .
+
0
generatedlayout
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
- COALESCE( "id", '<NULL>' )
+ id
+
-
- section_anchor20171220085838796
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."section" (anchor) sql=
+
+ section_intersection_13a1d3a9_897b_48fc_9714_e20439ad1ff6
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=Polygon checkPrimaryKeyUnicity='1' table="albion"."section_intersection" (geom) sql=
- section.anchor
+ section_intersection
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -4407,125 +5059,193 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
+
+
+
+
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
+
+
+
+
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
0
-
+
0
generatedlayout
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+ id
+
-
-
- 323136.61999999999534339
- 2074912.64999999990686774
- 323587.19000000000232831
- 2075090.92999999993480742
-
- section_geom20171210141834658
- dbname='template_project' host=localhost port=55432 sslmode=disable key='id' srid=32632 type=LineString table="albion"."section" (geom) sql=
+
+ section_polygon_f49e48f4_9101_4351_a07c_0a99748eaca2
+ dbname='template_project' host=127.0.0.1 port=55432 sslmode=disable key='"id"' srid=32632 type=MultiPolygon checkPrimaryKeyUnicity='1' table="albion"."section_polygon" (geom) sql=
- section.geom
+ section_polygon
+proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
@@ -4538,487 +5258,235 @@ def my_form_open(dialog, layer, feature):
false
+
+
+
+
+ dataset
+
+
+
+
+
+
+
+ +proj=utm +zone=32 +datum=WGS84 +units=m +no_defs
+ 3116
+ 32632
+ EPSG:32632
+ WGS 84 / UTM zone 32N
+ utm
+ WGS84
+ false
+
+
+
+
postgres
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+ 1
+ 1
+ 1
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
0
0
- 0
- id
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- .
+ 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
- .
+
+
+
+
+
0
- .
-
+
+
0
generatedlayout
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ true
+ false
+ 16
+ 50
+ 30
+ false
+ 0
+ 0
+
+
+ WGS84
+
+
+ 255
+ 0
+ 255
+ 255
+ 255
+ 255
+ 255
+
template_project
- /home/vmo/areva/albion
32632
- dbname=template_project host=localhost port=55432
+ /home/vmo/albion/nt
meters
m2
-
- +proj=longlat +datum=WGS84 +no_defs
- EPSG:4326
- 3452
- 1
-
false
-
- 0
- 255
- 255
- 255
- 255
- 255
- 255
-
-
- 1
-
- cell20171210155444151
- collar20170522101211588
- current_edge_section20171211173954570
- current_formation_section20171210182253618
- current_hole_section20171210181943739
- current_mineralization_section20171210141434594
- current_node_section20171211135743640
- current_radiometry_section20171210141136639
- edge20171211174003737
- group_cell20171210141649354
- possible_edge20171219072744468
- section_geom20171210141834658
- section_anchor20171220084145458
-
-
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
- disabled
-
- current_layer
-
-
- 2
- 2
- 2
- 2
- 2
- 2
- 2
- 2
- 2
- 2
- 2
- 2
- 2
-
-
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
- to_vertex_and_segment
-
- off
- 10
-
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
- 0.000000
-
-
+
+ 1
+
- 2
true
+ 2
+
+
+
+
+
+
+
+
+
+
+ 2019-08-23T18:21:56
+
+
+
diff --git a/test.py b/test.py
index b6b7dec..a41dee1 100644
--- a/test.py
+++ b/test.py
@@ -1,3 +1,4 @@
+from __future__ import print_function
# coding = utf-8
if __name__ == "__main__":
@@ -42,7 +43,8 @@
) as t
""")
for rec in cur.fetchall():
- print rec
+ # fix_print_with_import
+ print(rec)
#con = project.connect()
#cur = con.cursor()
diff --git a/test/__init__.py b/test/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/test/__main__.py b/test/__main__.py
new file mode 100644
index 0000000..59baf84
--- /dev/null
+++ b/test/__main__.py
@@ -0,0 +1,6 @@
+import os
+import re
+
+for f in os.listdir(os.path.dirname(__file__)):
+ if re.match('^[a-z].*\.py', f):
+ print(f)
diff --git a/test/end_node.py b/test/end_node.py
new file mode 100644
index 0000000..7ed3072
--- /dev/null
+++ b/test/end_node.py
@@ -0,0 +1,63 @@
+from __future__ import print_function
+# coding = utf-8
+
+
+SQL = """
+INSERT INTO albion.collar(id, geom, depth_) VALUES
+ (1, 'SRID=32632;POINT(0 0 0)'::geometry, 100),
+ (2, 'SRID=32632;POINT(100 0 0)'::geometry, 100),
+ (3, 'SRID=32632;POINT(200 0 0)'::geometry, 100),
+ (4, 'SRID=32632;POINT(300 0 0)'::geometry, 100),
+ (5, 'SRID=32632;POINT(0 100 0)'::geometry, 100)
+;
+SELECT albion.triangulate()
+;
+
+INSERT INTO albion.graph(id) VALUES
+ ('graph1')
+;
+INSERT INTO albion.node(id, graph_id, hole_id, from_, to_, geom) VALUES
+ (1, 'graph1', 2, 50, 100, albion.hole_piece(50, 100, '2')),
+ (2, 'graph1', 3, 0, 50, albion.hole_piece(0, 50, '3'))
+;
+INSERT INTO albion.edge(id, graph_id, start_, end_, geom) VALUES
+ (1, 'graph1', 1, 2, 'SRID=32632;LINESTRING(100 0 -75, 200 0 -25)'::geometry)
+;
+"""
+
+
+if __name__ == "__main__":
+ from albion.project import Project
+ import os
+ import sys
+ import time
+
+
+ project_name = "end_node_test"
+
+ if Project.exists(project_name):
+ Project.delete(project_name)
+
+ project = Project.create(project_name, 32632)
+ start = time.time()
+
+ with project.connect() as con:
+ cur = con.cursor()
+ for sql in SQL.split("\n;\n")[:-1]:
+ cur.execute(sql)
+ con.commit()
+
+ cur.execute("""
+ SELECT node_id, hole_id, st_astext(geom)
+ FROM albion.dynamic_end_node
+ WHERE hole_id !='5'
+ """)
+ for r in cur.fetchall():
+ print(r)
+
+
+
+
+
+
+
diff --git a/test/export.py b/test/export.py
new file mode 100644
index 0000000..0aa3626
--- /dev/null
+++ b/test/export.py
@@ -0,0 +1,19 @@
+if __name__ == "__main__":
+
+ from albion.project import Project
+ import os
+ import shutil
+
+ project = Project("tutorial_test")
+
+ with project.connect() as con:
+ cur = con.cursor()
+ cur.execute("select id from albion.cell")
+ if os.path.isdir('/tmp/min1000'):
+ shutil.rmtree('/tmp/min1000')
+ os.mkdir('/tmp/min1000')
+ cells = [r for r, in cur.fetchall()]
+ project.export_elementary_volume_obj('min1000', cells, '/tmp/min1000')
+ project.export_elementary_volume_dxf('min1000', cells, '/tmp/min1000')
+
+
diff --git a/test/import.py b/test/import.py
new file mode 100644
index 0000000..fa7e52e
--- /dev/null
+++ b/test/import.py
@@ -0,0 +1,29 @@
+from __future__ import print_function
+# coding = utf-8
+
+if __name__ == "__main__":
+ from albion.project import Project
+ import os
+ import sys
+ import time
+ import tempfile
+ import zipfile
+
+
+
+ project_name = "import_test"
+
+ if Project.exists(project_name):
+ Project.delete(project_name)
+
+ project = Project.create(project_name, 32632)
+ start = time.time()
+ zip_ref = zipfile.ZipFile(os.path.join(os.path.dirname(__file__), '..', 'data', 'nt.zip'), 'r')
+ zip_ref.extractall(tempfile.gettempdir())
+ zip_ref.close()
+ data_dir = os.path.join(tempfile.gettempdir(), 'nt')
+ print('###############################', data_dir)
+ project.import_data(data_dir)
+ project.triangulate()
+ project.create_section_view_0_90(4)
+
diff --git a/test/mineralisation.py b/test/mineralisation.py
new file mode 100644
index 0000000..92f6a72
--- /dev/null
+++ b/test/mineralisation.py
@@ -0,0 +1,38 @@
+
+"""
+create table albion.test_mineralization(
+ id varchar primary key default _albion.unique_id()::varchar,
+ hole_id varchar not null references _albion.hole(id) on delete cascade on update cascade,
+ level_ real,
+ from_ real,
+ to_ real,
+ oc real,
+ accu real,
+ grade real,
+ comments varchar,
+ geom geometry('LINESTRINGZ', $SRID))
+;
+
+insert into albion.test_mineralization(hole_id, level_, from_, to_, oc, accu, grade)
+select hole_id, (t.r).level_, (t.r).from_, (t.r).to_, (t.r).oc, (t.r).accu, (t.r).grade
+from (
+select hole_id, albion.segmentation(
+ array_agg(gamma order by from_),array_agg(from_ order by from_), array_agg(to_ order by from_),
+ 1., 1., 10) as r
+from _albion.radiometry
+group by hole_id
+) as t
+;
+
+update albion.test_mineralization set geom=albion.hole_piece(from_, to_, hole_id)
+;
+
+create view albion.current_test_mineralization_section as
+select row_number() over() as id, m.hole_id, h.collar_id, m.level_, m.oc, m.accu, m.grade, s.id as section_id,
+ (albion.to_section(m.geom, s.anchor, s.scale))::geometry('LINESTRING', $SRID) as geom
+from albion.test_mineralization as m
+join _albion.hole as h on h.id=m.hole_id
+join _albion.collar as c on c.id=h.collar_id
+join _albion.section as s on st_intersects(s.geom, c.geom)
+;
+"""
diff --git a/test/parent_graph.py b/test/parent_graph.py
new file mode 100644
index 0000000..7515ebf
--- /dev/null
+++ b/test/parent_graph.py
@@ -0,0 +1,95 @@
+from __future__ import print_function
+# coding = utf-8
+
+# (1)<--------------100 m----------------->(2)
+# 6||3
+#
+#
+#
+# _ -50m
+# | 5||2
+# |
+# 1||4
+# |
+# | _ -100 m
+
+SQL = """
+INSERT INTO albion.collar(id, geom, depth_) VALUES
+ (1, 'SRID=32632;POINT(0 0 0)'::geometry, 100),
+ (2, 'SRID=32632;POINT(100 0 0)'::geometry, 100),
+ (3, 'SRID=32632;POINT(100 100 0)'::geometry, 100)
+;
+INSERT INTO albion.cell(id, a, b, c, geom) VALUES
+ (1, 1, 2, 3, 'SRID=32632;POLYGON((0 0, 100 0, 100 100, 0 0))'::geometry)
+;
+REFRESH MATERIALIZED VIEW albion.all_edge
+;
+INSERT INTO albion.graph(id) VALUES
+ ('graph1')
+;
+INSERT INTO albion.node(id, graph_id, hole_id, from_, to_, geom) VALUES
+ (1, 'graph1', 1, 50, 100, 'SRID=32632;LINESTRING(0 0 -50, 0 0 -100)'::geometry),
+ (2, 'graph1', 2, 50, 60, 'SRID=32632;LINESTRING(100 0 -50, 100 0 -60)'::geometry),
+ (3, 'graph1', 2, 0, 50, 'SRID=32632;LINESTRING(100 0 -40, 100 0 -50)'::geometry)
+;
+INSERT INTO albion.graph(id, parent) VALUES
+ ('graph2', 'graph1')
+;
+INSERT INTO albion.node(id, graph_id, hole_id, from_, to_, geom) VALUES
+ (4, 'graph2', 1, 70, 80, 'SRID=32632;LINESTRING(0 0 -70, 0 0 -80)'::geometry),
+ (5, 'graph2', 2, 50, 60, 'SRID=32632;LINESTRING(100 0 -50, 100 0 -60)'::geometry),
+ (6, 'graph2', 2, 0, 10, 'SRID=32632;LINESTRING(100 0 0, 100 0 -10)'::geometry)
+;
+;
+"""
+
+
+if __name__ == "__main__":
+ from albion.project import Project
+ import os
+ import sys
+ import time
+
+
+ project_name = "parent_graph_test"
+
+ if Project.exists(project_name):
+ Project.delete(project_name)
+
+ project = Project.create(project_name, 32632)
+ start = time.time()
+
+ with project.connect() as con:
+ cur = con.cursor()
+ for sql in SQL.split("\n;\n")[:-1]:
+ cur.execute(sql)
+ con.commit()
+
+ cur.execute("""
+ UPDATE albion.metadata SET correlation_angle=1 ;
+ """)
+
+ cur.execute("""
+ SELECT start_, end_ FROM albion.possible_edge
+ """)
+ for s,e in cur.fetchall():
+ print(s,e)
+
+ cur.execute("""
+ INSERT INTO albion.edge(start_, end_, graph_id, geom) SELECT start_, end_, graph_id, geom FROM albion.possible_edge
+ """)
+
+ cur.execute("""
+ SELECT start_, end_ FROM albion.possible_edge
+ """)
+
+ edges = [(s,e) for s,e in cur.fetchall()]
+ print(edges)
+ assert(('1','2') in edges)
+ assert(('4','5') in edges)
+
+
+
+
+
+
diff --git a/test/tutorial.py b/test/tutorial.py
new file mode 100644
index 0000000..c84aa3c
--- /dev/null
+++ b/test/tutorial.py
@@ -0,0 +1,111 @@
+from __future__ import print_function
+# coding = utf-8
+
+if __name__ == "__main__":
+ from albion.project import Project
+ import os
+ import sys
+ import time
+ import tempfile
+ import zipfile
+ from osgeo import ogr
+
+ project_name = "tutorial_test"
+
+ if Project.exists(project_name):
+ Project.delete(project_name)
+
+ project = Project.create(project_name, 32632)
+ start = time.time()
+ zip_ref = zipfile.ZipFile(os.path.join(os.path.dirname(__file__), '..', 'data', 'nt.zip'), 'r')
+ zip_ref.extractall(tempfile.gettempdir())
+ zip_ref.close()
+ data_dir = os.path.join(tempfile.gettempdir(), 'nt')
+ project.import_data(data_dir)
+ project.create_section_view_0_90(4)
+ project.compute_mineralization(1000, 1, 1)
+
+ # import named section from file
+ with project.connect() as con:
+ driver = ogr.GetDriverByName('GPKG')
+ dataSource = driver.Open(os.path.join(os.path.dirname(__file__), 'tutorial_named_section.gpkg'), 0)
+ data = [(feature.GetField('section'), feature.GetGeometryRef().ExportToWkb().hex())
+ for feature in dataSource.GetLayer()]
+ cur = con.cursor()
+ cur.execute("delete from albion.named_section")
+ cur.executemany("""
+ insert into albion.named_section(section, geom)
+ values (%s, st_setsrid(%s::geometry, 32632))
+ """, data)
+ con.commit()
+
+
+ project.triangulate()
+
+ with project.connect() as con:
+ cur = con.cursor()
+ cur.execute("delete from albion.cell where aspect_ratio > 10")
+ con.commit()
+
+ with project.connect() as con:
+ cur = con.cursor()
+ cur.execute("select name from albion.layer")
+ layers = [r[0] for r in cur.fetchall()]
+ print(layers)
+
+ #for l in layers:
+ # project.refresh_section_geom(l)
+
+
+ project.new_graph('330')
+ project.new_graph('min1000', '330')
+
+ with project.connect() as con:
+ cur = con.cursor()
+ cur.execute("""
+ insert into albion.node(from_, to_, hole_id, graph_id)
+ select from_, to_, hole_id, '330' from albion.formation where code=330
+ """)
+ con.commit()
+
+ project.accept_possible_edge('330')
+ project.create_terminations('330')
+ project.create_volumes('330')
+
+ # test that all volumes are closed and positive
+ with project.connect() as con:
+ cur = con.cursor()
+ cur.execute("""
+ select cell_id from albion.volume where not albion.is_closed_volume(triangulation)
+ """
+ )
+ unclosed = cur.fetchall()
+ if len(unclosed):
+ print("unclosed volume for cells", unclosed)
+ assert(len(unclosed) == 0)
+ cur.execute("""
+ select count(1) from albion.volume where albion.volume_of_geom(triangulation) <= 0
+ """
+ )
+ assert(cur.fetchone()[0]==0)
+
+
+ with project.connect() as con:
+ cur = con.cursor()
+ cur.execute("""
+ insert into albion.node(from_, to_, hole_id, graph_id)
+ select from_, to_, hole_id, 'min1000' from albion.mineralization
+ """)
+
+ con.commit()
+
+ project.accept_possible_edge('min1000')
+ project.create_terminations('min1000')
+ project.create_volumes('min1000')
+
+ project.export_sections_obj('min1000', '/tmp/min1000_section.obj')
+ project.export_sections_obj('330', '/tmp/330_section.obj')
+
+
+
+
diff --git a/test/tutorial_named_section.gpkg b/test/tutorial_named_section.gpkg
new file mode 100644
index 0000000..2c4d226
Binary files /dev/null and b/test/tutorial_named_section.gpkg differ
diff --git a/viewer_3d/__main__.py b/viewer_3d/__main__.py
index d89b260..28c4d1f 100644
--- a/viewer_3d/__main__.py
+++ b/viewer_3d/__main__.py
@@ -1,6 +1,6 @@
-from PyQt4.QtGui import *
-from PyQt4.QtCore import *
+from qgis.PyQt.QtGui import *
+from qgis.PyQt.QtCore import *
import sys
from ..project import Project
from .viewer_3d import ViewerWindow
diff --git a/viewer_3d/camera.py b/viewer_3d/camera.py
index 0292da8..b9b1320 100644
--- a/viewer_3d/camera.py
+++ b/viewer_3d/camera.py
@@ -1,7 +1,8 @@
# -*- coding: UTF-8 -*-
-from PyQt4.QtCore import Qt
-from PyQt4.QtGui import QVector3D
+from builtins import object
+from qgis.PyQt.QtCore import Qt
+from qgis.PyQt.QtGui import QVector3D
class Camera(object):
"a simple camera"
diff --git a/viewer_3d/scene.py b/viewer_3d/scene.py
index aa167d1..d7679b5 100644
--- a/viewer_3d/scene.py
+++ b/viewer_3d/scene.py
@@ -1,11 +1,13 @@
# -*- coding: UTF-8 -*-
+from builtins import zip
+from builtins import range
import numpy
from OpenGL.GL import *
from OpenGL.GL import shaders
-from PyQt4.QtGui import *
-from PyQt4.QtCore import *
+from qgis.PyQt.QtGui import *
+from qgis.PyQt.QtCore import *
from .utility import computeNormals
from shapely import wkb
@@ -51,6 +53,7 @@ def __init__(self, project, param, texture_binder, parent=None):
"edge":None,
"section":None,
"volume":None,
+ "volume_section":None,
"error":None,
"end": None,
"inconsistency":None}
@@ -59,6 +62,7 @@ def __init__(self, project, param, texture_binder, parent=None):
"edge":None,
"section":None,
"volume":None,
+ "volume_section":None,
"error":None,
"end":None}
@@ -72,6 +76,7 @@ def __init__(self, project, param, texture_binder, parent=None):
"end":None}
self.nrml = {
"volume":None,
+ "volume_section":None,
"error":None}
self.__labels = []
@@ -133,14 +138,6 @@ def compileShaders(self):
gl_FragColor.rgb = mix(vec3(0.0), Idiff.xyz, edgeFactor());
gl_FragColor.a = 1. - uTransparency;
- //if(any(lessThan(vBC, vec3(0.02)))){
- // gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0);
- //}
- //else{
- // gl_FragColor = Idiff;
- //}
- //gl_FragColor = vec4(vBC.xyz, 1);//Idiff;
- //gl_FragColor = Idiff;
}
""", GL_FRAGMENT_SHADER)
@@ -237,7 +234,6 @@ def rendergl(self, leftv, upv, eye, height, context):
glDrawElementsui(GL_LINES, a)
glEnable(GL_DEPTH_TEST)
-
# render volume
if self.__param["transparency"] > 0.:
glDisable(GL_DEPTH_TEST)
@@ -291,6 +287,36 @@ def rendergl(self, leftv, upv, eye, height, context):
if self.__useProgram:
glUseProgram(0)
+ layer='volume_section'
+ if self.__param[layer]:
+ if self.__param[layer] != self.__old_param[layer]:
+ self.update(layer)
+ if self.vtx[layer] is not None and len(self.vtx[layer]):
+ glEnable(GL_COLOR_MATERIAL)
+ glDisable(GL_TEXTURE_2D)
+ glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, [7., 4., 4., 1.])
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, [7., 4., 4., 1.])
+ glColor4f(.7, .4, .4, 1.)
+ glVertexPointerf(self.vtx[layer])
+ glDisableClientState(GL_COLOR_ARRAY)
+ glDisable(GL_CULL_FACE)
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)
+ glNormalPointerf(self.nrml[layer])
+ glDrawElementsui(GL_TRIANGLES, self.idx[layer])
+ #if not self.__useProgram:
+ # glDisable(GL_LIGHTING)
+ # glDisableClientState(GL_COLOR_ARRAY)
+ # glColor4f(.1, .1, .1, 1.)
+ # glLineWidth(2)
+ # glEnable(GL_CULL_FACE)
+ # glPolygonMode(GL_FRONT,GL_LINE)
+ # glDrawElementsui(GL_TRIANGLES, self.idx[layer])
+ # glPolygonMode(GL_FRONT,GL_FILL)
+ # glDisable(GL_CULL_FACE)
+ # glEnableClientState(GL_COLOR_ARRAY)
+ # glEnable(GL_LIGHTING)
+ glDisable(GL_COLOR_MATERIAL)
+
# current section, highlight nodes
glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, [1., 1., 0., 1.])
glDisableClientState(GL_COLOR_ARRAY)
@@ -450,8 +476,7 @@ def update(self, layer):
cur.execute("""
select coalesce(st_collect(n.geom), 'GEOMETRYCOLLECTION EMPTY'::geometry)
from albion.section as s
- join albion.collar as c on st_intersects(s.geom, c.geom)
- join albion.hole as h on h.collar_id=c.id
+ join albion.hole as h on s.geom && h.geom and st_intersects(s.geom, st_startpoint(h.geom))
join albion.node as n on n.hole_id=h.id
where n.graph_id='{}'
""".format(self.__param["graph_id"])
@@ -513,6 +538,21 @@ def update(self, layer):
self.idx[layer] = numpy.require(numpy.arange(len(self.vtx[layer])).reshape((-1,3)), numpy.int32, 'C')
self.nrml[layer] = computeNormals(self.vtx[layer], self.idx[layer])
+ elif layer=='volume_section':
+ cur.execute("""
+ select st_collectionhomogenize(coalesce(st_collect(geom), 'GEOMETRYCOLLECTION EMPTY'::geometry))
+ from albion.volume_section
+ where graph_id='{}'
+ """.format(self.__param["graph_id"]))
+ geom = wkb.loads(bytes.fromhex(cur.fetchone()[0]))
+ self.vtx[layer] = numpy.require(numpy.array([tri.exterior.coords[:-1] for tri in geom]).reshape((-1,3)), numpy.float32, 'C')
+ if len(self.vtx[layer]):
+ self.vtx[layer] += self.__offset
+ self.vtx[layer][:,2] *= self.__param["z_scale"]
+ self.idx[layer] = numpy.require(numpy.arange(len(self.vtx[layer])).reshape((-1,3)), numpy.int32, 'C')
+ self.nrml[layer] = computeNormals(self.vtx[layer], self.idx[layer])
+
+
elif layer=='error':
cur.execute("""
select st_collectionhomogenize(coalesce(st_collect(triangulation), 'GEOMETRYCOLLECTION EMPTY'::geometry))
@@ -531,7 +571,7 @@ def update(self, layer):
self.__old_param[layer] = self.__param[layer]
def setGraph(self, graph_id):
- for layer in ['node', 'edge', 'volume', 'section', 'error', 'end']:
+ for layer in ['node', 'edge', 'volume', 'volume_section', 'section', 'error', 'end']:
if self.__param[layer] != self.__old_param[layer]:
self.update(layer)
self.__old_param["graph_id"] = graph_id
@@ -540,10 +580,10 @@ def setGraph(self, graph_id):
def setZscale(self, scale):
factor = float(scale)/self.__old_param["z_scale"]
- for layer in ['node', 'edge', 'volume', 'section', 'error', 'end']:
+ for layer in ['node', 'edge', 'volume', 'volume_section', 'section', 'error', 'end']:
if self.vtx[layer] is not None:
self.vtx[layer][:,2] *= factor
- if layer in ['volume', 'error']:
+ if layer in ['volume', 'volume_section', 'error']:
self.nrml[layer] = computeNormals(self.vtx[layer], self.idx[layer])
for scatter in self.__labels:
diff --git a/viewer_3d/utility.py b/viewer_3d/utility.py
index afca416..22826a5 100644
--- a/viewer_3d/utility.py
+++ b/viewer_3d/utility.py
@@ -1,5 +1,6 @@
# -*- coding: UTF-8 -*-
+from builtins import str
import sys
import re
import numpy
diff --git a/viewer_3d/viewer_3d.py b/viewer_3d/viewer_3d.py
index b43430a..590aac6 100644
--- a/viewer_3d/viewer_3d.py
+++ b/viewer_3d/viewer_3d.py
@@ -8,10 +8,11 @@
from OpenGL import GLU
-from PyQt4.QtOpenGL import QGLWidget, QGLPixelBuffer, QGLFormat
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4 import uic
+from PyQt5.QtOpenGL import QGLWidget, QGLFormat
+from qgis.PyQt.QtCore import Qt
+from qgis.PyQt.QtGui import QVector3D
+from qgis.PyQt.QtWidgets import QMessageBox, QMainWindow
+from qgis.PyQt import uic
import os
import re
@@ -33,6 +34,7 @@ def __init__(self, project=None, parent=None):
"end": False,
"edge": False,
"volume": False,
+ "volume_section": True,
"error": False,
"section": False,
"z_scale": 1,
@@ -51,14 +53,14 @@ def __init__(self, project=None, parent=None):
self.previous_pick = None
def refresh_data(self):
- if self.scene and self.__project.has_collar:
+ if self.scene and self.__project.has_hole:
self.resetScene(self.__project, False)
- for layer in ['node', 'edge', 'volume', 'section', 'error', 'end']:
+ for layer in ['node', 'edge', 'volume', 'volume_section', 'section', 'error', 'end']:
self.scene.update(layer)
self.update()
def resetScene(self, project, resetCamera=True):
- if project and project.has_collar:
+ if project and project.has_hole:
self.scene = Scene(project, self.__param, self.bindTexture, self)
if resetCamera:
at = self.scene.center
@@ -67,7 +69,7 @@ def resetScene(self, project, resetCamera=True):
self.camera = Camera(eye, at)
if self.__param['graph_id']:
- for layer in ['node', 'edge', 'volume', 'section', 'error', 'end']:
+ for layer in ['node', 'edge', 'volume', 'volume_section', 'section', 'error', 'end']:
self.scene.update(layer)
self.update()
else:
@@ -112,6 +114,11 @@ def toggle_volumes(self, state):
self.__param["volume"] = state
self.update()
+ def toggle_volumes_section(self, state):
+ self.__param["volume_section"] = state
+ self.update()
+
+
def toggle_errors(self, state):
self.__param["error"] = state
self.update()
diff --git a/viewer_3d/viewer_controls.py b/viewer_3d/viewer_controls.py
index f144baf..8e1a267 100644
--- a/viewer_3d/viewer_controls.py
+++ b/viewer_3d/viewer_controls.py
@@ -1,10 +1,7 @@
# coding=UTF-8
import os
-#from qgis.core import *
-#from qgis.gui import *
-from PyQt4.QtCore import *
-from PyQt4.QtGui import *
-from PyQt4 import uic
+from qgis.PyQt.QtWidgets import QWidget, QMenu
+from qgis.PyQt import uic
from functools import partial
class ViewerControls(QWidget):
@@ -24,6 +21,7 @@ def __init__(self, viewer, iface=None, parent=None):
('edges', self.__viewer.toggle_edges, True),
('ends', self.__viewer.toggle_ends, True),
('volumes', self.__viewer.toggle_volumes, False),
+ ('volumes sections', self.__viewer.toggle_volumes_section, True),
('errors', self.__viewer.toggle_errors, False),
]:
a = menu.addAction(l)