Skip to content

Commit

Permalink
v.in.survey: module startup fix (#381)
Browse files Browse the repository at this point in the history
* fix order (MRO) for bases glob, files

* order (MRO) for bases glob, layer

* order (MRO) for bases glob, files

* order (MRO) for bases layer, Merge, dxf

* order (MRO) for bases glob, layer, Merge_init, Merge, dxf, dxf_layer_merged, dxf_layer

* make a 'done_lyrs' var a global var

* comment unused var

* fix 'final' local var

* set vector area map type 'v.centroid' command overwrite flag

* remove duplicate checking vector line map type name

* fix merge vector maps
  • Loading branch information
tmszi committed Jan 14, 2021
1 parent 41c4cb4 commit 2cb5f62
Showing 1 changed file with 186 additions and 48 deletions.
234 changes: 186 additions & 48 deletions grass7/vector/v.in.survey/v.in.survey.py
Expand Up @@ -180,15 +180,154 @@
#% guisection: DXF conversion
#%end

import sys
import os
import string
import math
import fileinput
import os
import subprocess
from functools import reduce

import grass.script as grass
from grass.pygrass.messages import get_msgr
import grass.script.vector as gvect


class MakeSameVarcharColTypeLengthMapTables:
"""Make same varchar column type length value in tables with same
columns structure
Same varchar column type length value is needed for 'v.patch'
command.
:param list tables: input tables list
"""

def __init__(self, tables):
self.process_tables(tables=tables)

def get_clen_value(self, col):
"""Get column name with column length as tuple
:param dict col: column definition
{'str_1': {'ctype': 'CHARACTER', 'clen': '8'}
:return list: column name with column length as tuple
[('str_1', 8)]
"""

return [(d[0], d[1]['clen']) for d in col.items()]

def get_symm_diff_cols(self, a, b):
"""Get symmetrict difference between two columns from two another
tables
:param dict a: column definition
{'str_1': {'ctype': 'CHARACTER', 'clen': '8'}
:param dict b: column definition
{'str_1': {'ctype': 'CHARACTER', 'clen': '12'}
:return set: symmetric difference between cols
{('str_1', '12'), ('str_1', '8')}
"""

if isinstance(a, dict):
return set(self.get_clen_value(col=a)) ^ \
set(self.get_clen_value(col=b))
else:
return a ^ set(self.get_clen_value(col=b))

def get_same_col_from_tables(self, tables_cols, col):
"""
Get same column definition from different tables
:param list tables_cols: tables columns definition from different
tables
[
'{cat': {'ctype': 'INTEGER', 'clen': '20'},
'dbl_1': {'ctype': 'DOUBLE PRECISION', 'clen': '20'},
'dbl_2': {'ctype': 'DOUBLE PRECISION', 'clen': '20'},
'str_1': {'ctype': 'CHARACTER', 'clen': '14'}},
'{cat': {'ctype': 'INTEGER', 'clen': '20'},
'dbl_1': {'ctype': 'DOUBLE PRECISION', 'clen': '20'},
'dbl_2': {'ctype': 'DOUBLE PRECISION', 'clen': '20'},
'str_1': {'ctype': 'CHARACTER', 'clen': '8'}},
...
]
:param str col: col name e.g. 'str_1'
:return list cols: list of same column with definition from
different tables
[
{'str_1': {'ctype': 'CHARACTER', 'clen': '14'}},
{'str_1': {'ctype': 'CHARACTER', 'clen': '8'}},
...
]
"""

cols = []
for table in tables_cols:
cols.append({col: table[col]})
return cols

def process_tables(self, tables):
"""Get difference between varchar column type length value
(max value) across different tables (same columns structure)
and change varchar type column length value accodring max length
value in the input other tables.
Same varchar column type length value is needed for 'v.patch'
command.
:param list tables: list of input tables (with same columns
structure)
:return None
"""

result = []
for index, table in enumerate(tables):
result.append({})
stdout, stderr = grass.start_command(
'db.describe', flags='c', table=table,
stdout=subprocess.PIPE,
).communicate()
if stdout:
stdout = grass.decode(stdout)
for row in stdout.split('\n'):
if row.count(':') == 3:
col, ctype, clen = row.split(':')[-3:]
result[index][col.strip()] = {
'ctype': ctype, 'clen': clen,
}

if result and len(result) > 1:
for col in result[0].keys():
sym_diff = reduce(
self.get_symm_diff_cols,
self.get_same_col_from_tables(
tables_cols=result, col=col,
),
)
if sym_diff and len(sym_diff) > 1:
col, clen = max(sym_diff, key=lambda i: int(i[1]))
for index, t in enumerate(result):
if t[col]['clen'] == clen:
table = tables[index]
break
for table in list(filter(lambda i: i != table, tables)):
grass.run_command(
'v.db.addcolumn', map=table,
columns="{}_ varchar({})".format(col, clen),
)
grass.run_command(
'v.db.update', map=table,
column="{}_".format(col), query_column=col,
)
grass.run_command(
'v.db.dropcolumn', map=table, columns=col,
)
grass.run_command(
'v.db.renamecolumn', map=table,
column="{0}_,{0}".format(col),
)


class test:
Expand Down Expand Up @@ -478,7 +617,7 @@ def open_output(self, skip_blank_test, dxf):
# ****** #


class skip(glob, test, files):
class skip(test, files):
layers = 0
existing = False
lyr_names = '' # names of the layers to be analyzed for merging
Expand Down Expand Up @@ -625,8 +764,8 @@ def test_existence(self, layer_name, final):
skip = False
mapset = grass.gisenv()['MAPSET']

# make fatal error if there are any existing layers during data import
if (overwrite_all is False and self.final is False
# make fatal error if there are any existing layers during data import
if (overwrite_all is False and final is False
and grass.find_file(layer_name, element='vector', # etc
mapset=mapset)['file']):
msgr.fatal(_("Vector layer <" + layer_name + "> exists. Please"
Expand Down Expand Up @@ -662,10 +801,19 @@ def make_new(self):
self.test_existence(layer.name, False) # test layer existence
# add centroids and create polygon layer
grass.run_command('v.centroids',
input=layer_name, output=layer.name)
input=layer_name, output=layer.name,
overwrite=overwrite_all)
# remove temporary line layer
grass.run_command('g.remove', type='vector',
name=layer_name, flags='f')
elif self.vector == 'L':
# add categories to line layer
grass.run_command('v.category', input=layer_name,
option='add', type='line', output=layer.name,
overwrite=overwrite_all)
# remove the layer without cats
grass.run_command('g.remove',
type='vector', name=layer_name, flags='f')

if self.vformat == 'standard':
self.set_attribute_table()
Expand All @@ -692,7 +840,7 @@ def setup_unit(self, remove_suffix):

def check_number_pts(self):
if layer.vector == 'L' and layer.n_pts < 2:
can_be_broken = done_lyrs.readlines()[-1]
# can_be_broken = done_lyrs.readlines()[-1]
msgr.fatal(_("Not enough points to make line layer <"
+ layer.name + ">."))
if layer.vector == 'B' and layer.n_pts < 3:
Expand All @@ -713,7 +861,6 @@ def standard_header(self):
for num, line in enumerate(fileinput.FileInput(self.filename, # etc
inplace=2)):
if num == 0:
print("VERTI:")
print(layer.vector + ' ' + str(layer.n_pts))
print(line.strip('\n'))
else:
Expand Down Expand Up @@ -757,16 +904,6 @@ def write(self, i):

# add atrribute table with the name of the layer
def set_attribute_table(self):
if self.vector == 'L':
line_layer = layer.name + '_tmp' # suffix '_tmp' to the line
self.test_existence(line_layer, False) # test layer existence
# add categories to line layer
grass.run_command('v.category', input=line_layer,
option='add', type='line', output=layer.name)
# remove the layer without cats
grass.run_command('g.remove',
type='vector', name=line_layer, flags='f')

# add table with the name column
grass.run_command('v.db.addtable',
map=layer.name, columns='lyr_name varchar(15)')
Expand Down Expand Up @@ -802,7 +939,7 @@ def write2(self, vformat, outfile, index):
# ****** #


class Merge_init(glob, layer): # Functionality for merging layers
class Merge_init(layer): # Functionality for merging layers
item = ''
n_items = 0
len_item = [] # array of length of layers' names
Expand Down Expand Up @@ -837,7 +974,6 @@ class Merge(Merge_init, layer):

def __init__(self, export2dxf):
self.export2dxf = export2dxf

if sum(Merge_init.len_item) > 0:
if Merge.init_add is True:
# export to DXF after merging
Expand Down Expand Up @@ -911,15 +1047,17 @@ def outfiles(self):
if Merge.wait4 is True and layer.name[:n_item] == Merge_init.item[i]:
merge_file = Merge.filename[i]
# set up name of current file to be merged
add_file_name = files(layer.name + '_bckp').path2('txt')
if layer.vector == 'P':
add_file_name = files(layer.name).path2('txt')
else:
add_file_name = files(layer.name + '_bckp').path2('txt')
if layer.vector == 'B':
subtract = -1
else:
subtract = 0
# add merged items to list of point number in the layer
Merge.n_pts[i].append(layer.n_pts + subtract)
Merge.init_done = False

# test if file to be added is not blank
with open(add_file_name, 'r') as add_file:
test(add_file).blank(False)
Expand All @@ -940,26 +1078,26 @@ def outfiles(self):
# merge layers according to pattern items
def layers(self):
if sum(Merge_init.len_item) > 0:
for i in range(0, Merge_init.n_items):
if Merge.name[i] == '':
msgr.warning(_("There are no layers to merge into <" # etc
+ Merge_init.item[i] + ">."))
continue

# merge layers to temporary layer
grass.run_command('v.patch',
input=Merge.name[i],
output=Merge_init.item[i]+"_tmp",
flags='e', overwrite=True)
# remove original dataset
grass.run_command('g.remove',
type='vector', name=Merge.name[i], flags='f')
if not Merge.name:
msgr.warning(_("There are no layers to merge into <" # etc
+ Merge_init.item[0] + ">."))
MakeSameVarcharColTypeLengthMapTables(tables=Merge.name)
# merge layers to temporary layer
grass.run_command('v.patch',
input=Merge.name,
output=Merge_init.item[0] + '_tmp',
flags='e', overwrite=True)
for map in Merge.name:
grass.run_command(
'g.remove', flags='f', type='vector',
name=map,
)
return 0

# clean topology
def clean_topology(self):
if sum(Merge_init.len_item) > 0:
for i in range(0, Merge.n_items):
for i in range(0, 1):
if Merge.name[i] != '': # just for merged layers

# find out code to recognize a type of the vector layer:
Expand Down Expand Up @@ -993,7 +1131,7 @@ def clean_topology(self):
# ****** #


class dxf(glob, files):
class dxf(files):
# based on v.out.dxf by Chuck Ehlschlaeger, Radim Blazek and Martin Landa
export2 = False
File = '' # dxf file
Expand All @@ -1005,7 +1143,7 @@ def __init__(self, export2, File, unit, textsize):
dxf.export2 = export2
dxf.File = File
dxf.unit = unit
dxf.textsize = textsize
dxf.textsize = float(textsize)

# open dxf file
if dxf.export2 is True:
Expand Down Expand Up @@ -1203,14 +1341,13 @@ class dxf_layer_merged(Merge):

def __init__(self, i):
self.i = i

dxf_layer_merged.name = Merge_init.item[i]
dxf_layer_merged.vector = Merge.vector[i]
dxf_layer_merged.n_pts = Merge.n_pts[i]
dxf_layer_merged.vector = Merge.vector[i] if Merge.vector else ''
dxf_layer_merged.n_pts = Merge.n_pts[i] if Merge.n_pts else ''
Merge.wait4 = False


class dxf_layer(layer, Merge, dxf): # *** make separate dxf layers *** #
class dxf_layer(Merge, dxf): # *** make separate dxf layers *** #
color = 1 # layer color (1-255). 0 not recognized by AutoCAD Civil 2015.
n = 0 # number of the layers
name = [] # list of layers for drawing entities
Expand Down Expand Up @@ -1282,8 +1419,8 @@ def setup_color(self):


class finalize_dxf(
inputs, layer, Merge_init, Merge, dxf,
dxf_layer_merged, dxf_layer):
inputs, dxf, dxf_layer_merged,
):

def __init__(self):
dxfs.end_tables() # close the section of the tables
Expand Down Expand Up @@ -1597,6 +1734,7 @@ def main():
global dxfs
global text_ratio # size of text compared to screen = 1
global centered
global done_lyrs
text_ratio = .003
centered = 4

Expand Down

0 comments on commit 2cb5f62

Please sign in to comment.