From c62eec5ddb23e04929bc414d039cd44222c4a8d5 Mon Sep 17 00:00:00 2001 From: Freek Boersma Date: Wed, 16 Oct 2019 11:46:55 +0200 Subject: [PATCH] First commit --- .../inspectionProfiles/profiles_settings.xml | 6 + .idea/misc.xml | 4 + .idea/modules.xml | 8 + .idea/sldextract.iml | 11 ++ .idea/workspace.xml | 141 +++++++++++++++ DBaccess.py | 24 +++ Pipfile | 13 ++ Pipfile.lock | 66 +++++++ __pycache__/DBaccess.cpython-37.pyc | Bin 0 -> 991 bytes pseudocode.txt | 24 +++ querytester.py | 15 ++ sldextract.py | 169 ++++++++++++++++++ 12 files changed, 481 insertions(+) create mode 100644 .idea/inspectionProfiles/profiles_settings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/sldextract.iml create mode 100644 .idea/workspace.xml create mode 100644 DBaccess.py create mode 100644 Pipfile create mode 100644 Pipfile.lock create mode 100644 __pycache__/DBaccess.cpython-37.pyc create mode 100644 pseudocode.txt create mode 100644 querytester.py create mode 100644 sldextract.py diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..a5e6ae4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..d8ce246 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/sldextract.iml b/.idea/sldextract.iml new file mode 100644 index 0000000..1a1e748 --- /dev/null +++ b/.idea/sldextract.iml @@ -0,0 +1,11 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..ebef4fe --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1569938389317 + + + + \ No newline at end of file diff --git a/DBaccess.py b/DBaccess.py new file mode 100644 index 0000000..1fba60b --- /dev/null +++ b/DBaccess.py @@ -0,0 +1,24 @@ +import psycopg2 + +# Initialize database parameters +host = "metis.geodan.nl" +user = "freekb" +dbname = "research" +port = "5432" + +mapping = {"OSM_Roads": "freeks_schema.osmweg"} + + +class DBConnect: + + def __init__(self, host="", user="", dbname="", port=""): + self.conn = psycopg2.connect("host={} user={} dbname={} port={}".format(host, user, dbname, port)) + self.cur = self.conn.cursor() + + def do_query(self, query): + self.cur.execute(query) + return self.cur.fetchall() + + def close(self): + self.cur.close() + self.conn.close() diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..8bb7cb6 --- /dev/null +++ b/Pipfile @@ -0,0 +1,13 @@ +[[source]] +name = "pypi" +url = "https://pypi.org/simple" +verify_ssl = true + +[dev-packages] + +[packages] +lxml = "*" +psycopg2 = "*" + +[requires] +python_version = "3.7" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..4725225 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,66 @@ +{ + "_meta": { + "hash": { + "sha256": "d721757815fbdc8bde065e39774ca7edbc74b884e38ad2c8978a1800ad041af5" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.7" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "lxml": { + "hashes": [ + "sha256:02ca7bf899da57084041bb0f6095333e4d239948ad3169443f454add9f4e9cb4", + "sha256:096b82c5e0ea27ce9138bcbb205313343ee66a6e132f25c5ed67e2c8d960a1bc", + "sha256:0a920ff98cf1aac310470c644bc23b326402d3ef667ddafecb024e1713d485f1", + "sha256:17cae1730a782858a6e2758fd20dd0ef7567916c47757b694a06ffafdec20046", + "sha256:17e3950add54c882e032527795c625929613adbd2ce5162b94667334458b5a36", + "sha256:1f4f214337f6ee5825bf90a65d04d70aab05526c08191ab888cb5149501923c5", + "sha256:2e8f77db25b0a96af679e64ff9bf9dddb27d379c9900c3272f3041c4d1327c9d", + "sha256:4dffd405390a45ecb95ab5ab1c1b847553c18b0ef8ed01e10c1c8b1a76452916", + "sha256:6b899931a5648862c7b88c795eddff7588fb585e81cecce20f8d9da16eff96e0", + "sha256:726c17f3e0d7a7200718c9a890ccfeab391c9133e363a577a44717c85c71db27", + "sha256:760c12276fee05c36f95f8040180abc7fbebb9e5011447a97cdc289b5d6ab6fc", + "sha256:796685d3969815a633827c818863ee199440696b0961e200b011d79b9394bbe7", + "sha256:891fe897b49abb7db470c55664b198b1095e4943b9f82b7dcab317a19116cd38", + "sha256:a471628e20f03dcdfde00770eeaf9c77811f0c331c8805219ca7b87ac17576c5", + "sha256:a63b4fd3e2cabdcc9d918ed280bdde3e8e9641e04f3c59a2a3109644a07b9832", + "sha256:b0b84408d4eabc6de9dd1e1e0bc63e7731e890c0b378a62443e5741cfd0ae90a", + "sha256:be78485e5d5f3684e875dab60f40cddace2f5b2a8f7fede412358ab3214c3a6f", + "sha256:c27eaed872185f047bb7f7da2d21a7d8913457678c9a100a50db6da890bc28b9", + "sha256:c81cb40bff373ab7a7446d6bbca0190bccc5be3448b47b51d729e37799bb5692", + "sha256:d11874b3c33ee441059464711cd365b89fa1a9cf19ae75b0c189b01fbf735b84", + "sha256:e9c028b5897901361d81a4718d1db217b716424a0283afe9d6735fe0caf70f79", + "sha256:fe489d486cd00b739be826e8c1be188ddb74c7a1ca784d93d06fda882a6a1681" + ], + "index": "pypi", + "version": "==4.4.1" + }, + "psycopg2": { + "hashes": [ + "sha256:128d0fa910ada0157bba1cb74a9c5f92bb8a1dca77cf91a31eb274d1f889e001", + "sha256:227fd46cf9b7255f07687e5bde454d7d67ae39ca77e170097cdef8ebfc30c323", + "sha256:2315e7f104681d498ccf6fd70b0dba5bce65d60ac92171492bfe228e21dcc242", + "sha256:4b5417dcd2999db0f5a891d54717cfaee33acc64f4772c4bc574d4ff95ed9d80", + "sha256:640113ddc943522aaf71294e3f2d24013b0edd659b7820621492c9ebd3a2fb0b", + "sha256:897a6e838319b4bf648a574afb6cabcb17d0488f8c7195100d48d872419f4457", + "sha256:8dceca81409898c870e011c71179454962dec152a1a6b86a347f4be74b16d864", + "sha256:b1b8e41da09a0c3ef0b3d4bb72da0dde2abebe583c1e8462973233fd5ad0235f", + "sha256:cb407fccc12fc29dc331f2b934913405fa49b9b75af4f3a72d0f50f57ad2ca23", + "sha256:d3a27550a8185e53b244ad7e79e307594b92fede8617d80200a8cce1fba2c60f", + "sha256:f0e6b697a975d9d3ccd04135316c947dd82d841067c7800ccf622a8717e98df1" + ], + "index": "pypi", + "version": "==2.8.3" + } + }, + "develop": {} +} diff --git a/__pycache__/DBaccess.cpython-37.pyc b/__pycache__/DBaccess.cpython-37.pyc new file mode 100644 index 0000000000000000000000000000000000000000..65afcf2f40d89a3a2176d5a1a82289628bdf08de GIT binary patch literal 991 zcmZuw!EVz)5Zzs`9VetjY9-WTxgg9ThXNNwQPou979k-nE2EXWyJ=b+JM22B4dz7t zgXG9B?UfV1z=;{Vp-?f=%#J;?GjHBFCp$Ym0X(KIK5 zXeOu*1k+puIu!gh(UI<~i0*u4BGmLPN#dW7PsYo^%v2X{cy3Ca6~iJI(Zm|_;Y`HV zIFng575w?Lr-usDx5B|W26d0X7y``*H0x@ngB69AT!$+nc-s^j#?Y|myQe3kvM7wI zJW(OsM8Pu#9f7*XU@Eevnyy(*YgPv}-|!8si41CT8Lat+fFEiC1=)D{a9XMgWkNf7)c@@&)u~u=jVr_qi)(qlhV$z%5!`nBDJutv_60{2|afvpLmX? zJ;%a6YRh_#MZXif12BIbjb5bhAnMYVu=KQ4irTvSrt!@-eILig!%_YX(IZGwW8H-aawyP@g_zd?Lgdj%#~4#%7}PkDmBgWJYg2u_Tk5cvDeKct+|hHV_nK7Fo35UQ2l>EZ4(rQ z3=}*OSOaPwoEFpu0^qSVMX%Y{Ev!)GB`_C3c0wCGcYxSE2%+9!=+WiimYC-DIN=t_ zxMOhNQsPG-rSC~OEA=8rzb|33EN>$g=d-(Lu*+ZFakUn?usBo~)FI56^?1yicS&S% iTNYy$|CbgwX!~gJ&i{(}_+<;^71HJKRvd8J{Mc`%gWb&l literal 0 HcmV?d00001 diff --git a/pseudocode.txt b/pseudocode.txt new file mode 100644 index 0000000..e8d95c0 --- /dev/null +++ b/pseudocode.txt @@ -0,0 +1,24 @@ +for each namedLayer: + layerToQuery = + if child is namedStyle: + print(Dit is een Namedstyle, weet niet wat ik moet doen) + if child is UserStyle: + for each FeatureTypeStyle: + for each Rule: + if filter exists: + check for and / or + check filter type (equality, >, <) + check min scale, max scale + + + +for each userLayer: + negeer voor nu + + +TODO: + +ogc:function? +spatial operators? +userlayers +geen filter in een rule? \ No newline at end of file diff --git a/querytester.py b/querytester.py new file mode 100644 index 0000000..14e7c0e --- /dev/null +++ b/querytester.py @@ -0,0 +1,15 @@ +import DBaccess + +db = DBaccess.DBConnect(DBaccess.host, DBaccess.user, DBaccess.dbname, DBaccess.port) + +query = """ +CREATE TABLE freeks_schema.pytest AS( +SELECT * +FROM freeks_schema.osmweg +LIMIT 10) +""" + +db.cur.execute(query) +db.conn.commit() +db.close() + diff --git a/sldextract.py b/sldextract.py new file mode 100644 index 0000000..3aaea20 --- /dev/null +++ b/sldextract.py @@ -0,0 +1,169 @@ +from lxml import etree +import math + + +def sld_to_rules(path): + """ + Takes an SLD file from a specified path. + Returns a list of Layer objects, which contain a list of Rules, which contain a list of Filters. + """ + tree = etree.parse(path) + root = tree.getroot() + + layers = [] + for layer in root.iter('{*}NamedLayer'): + rules = [] + for rule in layer.iter('{*}Rule'): + + # Ignore labels, we just want features FOR NOW + if rule.find('{*}TextSymbolizer') is not None: + continue + + # Get min/max scale denominator, if they exist + min_scale_el = rule.find('{*}MinScaleDenominator') + if min_scale_el is None: + min_scale = 0 + else: + min_scale = int(min_scale_el.text) + + max_scale_el = rule.find('{*}MaxScaleDenominator') + if max_scale_el is None: + max_scale = math.inf + else: + max_scale = int(max_scale_el.text) + + # Assume there is one Filter per Rule + filt = rule.find('{*}Filter') + filters = [] + + # Check for And/Or, otherwise None + if filt.find('{*}Or') is not None: + logical = "or" + elif filt.find('{*}And') is not None: + logical = "and" + else: + logical = None + + # Add Filter criteria to list + filters += get_filters("=", filt.iterfind('.//{*}PropertyIsEqualTo')) + filters += get_filters("<", filt.iterfind('.//{*}PropertyIsLessThan')) + filters += get_filters("<", filt.iterfind('.//{*}PropertyIsLessThanOrEqualTo')) + filters += get_filters(">", filt.iterfind('.//{*}PropertyIsGreaterThan')) + filters += get_filters(">", filt.iterfind('.//{*}PropertyIsGreaterThanOrEqualTo')) + + rules.append(Rule(min_scale, max_scale, logical, filters)) + layers.append(Layer(layer.find('{*}Name').text, rules)) + return layers + + +def get_filters(logic_string, sld_element): + """ + Returns list of Filter objects per rule + """ + + filts = [] + for sub_element in sld_element: + field = sub_element.find('.//{*}PropertyName').text + value = sub_element.find('.//{*}Literal').text + if is_number(value): + value = float(value) + current_filter = Filter(logic_string, field, value) + filts.append(current_filter) + return filts + + +def is_number(string): + """ + Check whether a string is a number + """ + + try: + float(string) + return True + except ValueError: + return False + + +class Filter: + """ + Filter to be used in WHERE clause + """ + + def __init__(self, logical_string, field, value): + self.logical_string = logical_string + self.field = field + self.value = value + + +class Rule: + """ + Rule derived from SLD file + """ + + def __init__(self, min_scale=0, max_scale=math.inf, logical=None, filters=[]): + self.min_scale = min_scale + self.max_scale = max_scale + self.logical = logical + self.filters = filters + + def scale_select(self, input_denom): + """ + Returns input for the WHERE clause based on scale denominator + """ + + clause = "" + if self.min_scale <= input_denom <= self.max_scale: + if len(self.filters) > 0: + if self.logical is None: + clause += "({} {} {})".format(self.filters[0].field, + self.filters[0].logical_string, + self.filters[0].value) + else: + clause += "(" + for fil in self.filters: + clause += "({} {} {}) {} ".format(fil.field, + fil.logical_string, + fil.value, + self.logical) + clause = clause[:-len(" {} ".format(self.logical))] + clause += ")" + return clause + + +class Layer: + """ + Layer on which the rules are applicable + """ + + def __init__(self, name="", rules=[]): + self.name = name + self.rules = rules + + def make_query(self, input_denom): + """ + Returns WHERE clause for query based on scale input + """ + + query = "SELECT * FROM {} WHERE (".format(self.name) + for rul in self.rules: + where_sub = rul.scale_select(input_denom) + + # Rule.scale_select() might return None + if type(where_sub) is str: + + # Prevent repetition in query (e.g. because of lines and fills) + if where_sub not in query: + query += rul.scale_select(input_denom) + query += " OR " + + query = query[:-4] + query += ")" + return query + + +if __name__ == "__main__": + for layr in sld_to_rules('./slds/85_89.sld'): + print(layr.make_query(1000000)) + #for ru in layr.rules: + # print(ru.min_scale, ru.max_scale) + # print(ru.scale_select(2000000))