diff --git a/.gitignore b/.gitignore index 58349bf..b1ae217 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ dist/ downloads/ eggs/ .eggs/ +lib/ lib64/ parts/ sdist/ diff --git a/accuracy_test/run_test.js b/accuracy_test/run_test.js index 27d317a..8f815ef 100644 --- a/accuracy_test/run_test.js +++ b/accuracy_test/run_test.js @@ -1,4 +1,4 @@ -const addressParser = require('./../web/src/lib/ogcio-parser'); +const addressParser = require('./../web/src/lib/address-parser'); const Promise = require('bluebird'); const request = Promise.promisifyAll(require('request')); diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index b7a18a2..0000000 --- a/package-lock.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "mgrs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", - "integrity": "sha1-+5FYjnjJACVnI5XLQLJffNatGCk=" - }, - "proj4": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.5.0.tgz", - "integrity": "sha512-XZTRT7OPdLzgvtTqL8DG2cEj8lYdovztOwiwpwRSYayOty5Ipf3H68dh/fiL+HKDEyetmQSMhkkMGiJoyziz3w==", - "requires": { - "mgrs": "1.0.0", - "wkt-parser": "1.2.3" - } - }, - "wkt-parser": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.2.3.tgz", - "integrity": "sha512-s7zrOedGuHbbzMaQOuf8HacuCYp3LmmrHjkkN//7UEAzsYz7xJ6J+j/84ZWZkQcrRqi3xXyuc4odPHj7PEB0bw==" - } - } -} diff --git a/web/src/App.vue b/web/src/App.vue index 0931962..a93e0c9 100644 --- a/web/src/App.vue +++ b/web/src/App.vue @@ -4,7 +4,8 @@ 香港地址解析器 Hong Kong Address Parser (Beta - Release 0.3) - 解析地址 + 單次處理 + 大量處理 反映意見 diff --git a/web/src/assets/pin-selected.png b/web/src/assets/pin-selected.png deleted file mode 100644 index c63ad0b..0000000 Binary files a/web/src/assets/pin-selected.png and /dev/null differ diff --git a/web/src/components/SearchFilter.vue b/web/src/components/SearchFilter.vue index 6e8cc6e..621c8f4 100644 --- a/web/src/components/SearchFilter.vue +++ b/web/src/components/SearchFilter.vue @@ -1,5 +1,5 @@ +}; + \ No newline at end of file diff --git a/web/src/lib/ogcio-parser.js b/web/src/lib/address-parser.js similarity index 98% rename from web/src/lib/ogcio-parser.js rename to web/src/lib/address-parser.js index f503406..3f58a4b 100644 --- a/web/src/lib/ogcio-parser.js +++ b/web/src/lib/address-parser.js @@ -107,13 +107,7 @@ function eliminateLangKeys(data) { const result = {}; for (const key of Object.keys(data)) { const refinedKey = key.replace(/(^Chi|^Eng)/,''); - // eliminate with recursion - if (typeof(data[key]) === 'object') { - result[refinedKey] = eliminateLangKeys(data[key]); - } else { - result[refinedKey] = data[key]; - } - + result[refinedKey] = data[key]; } return result; } diff --git a/web/src/lib/address-resolver.js b/web/src/lib/address-resolver.js deleted file mode 100644 index 297ef06..0000000 --- a/web/src/lib/address-resolver.js +++ /dev/null @@ -1,87 +0,0 @@ - -import ogcioParser from './ogcio-parser'; -import * as AddressFactory from './models/address-factory'; -import proj4 from 'proj4'; -import ProjConvertor from '../utils/proj-convertor'; - -const OGCIO_RECORD_COUNT = 200; -const NEAR_THRESHOLD = 0.03; // 30 metre - -export default { - queryAddress: async (address) => { - // Fetch result from OGCIO - const ogcioURL = `https://www.als.ogcio.gov.hk/lookup?q=${address}&n=${OGCIO_RECORD_COUNT}`; - - const ogcioRes = await fetch(ogcioURL, { - headers: { - "Accept": "application/json", - "Accept-Language": "en,zh-Hant", - "Accept-Encoding": "gzip" - } - }); - const ogcioData = await ogcioRes.json(); - - // Fetch result from GeoData Portal of Land Department - const landsURL = `https://geodata.gov.hk/gs/api/v1.0.0/locationSearch?q=${address}`; - const landsRes = await fetch(landsURL); - const landsData = await landsRes.json(); - - const landRecords = []; - for (const data of landsData) { - let wgsLng, wgslat; - [wgsLng, wgslat] = ProjConvertor.projTransform('EPSG:2326', 'EPSG:4326', [data.x, data.y]); - data.lat = wgslat - data.lng = wgsLng - landRecords.push(AddressFactory.createAddress('land', data)); - } - const sortedResults = []; - const sortedOgcioRecords = (await ogcioParser.searchResult(address, ogcioData)).map(record => AddressFactory.createAddress('ogcio', record)); - // P.S. Result source (OGCIO/Land Department) should be displayed to user - // this.results['source'] = ... - console.log('OGCIO Best match: ' + sortedOgcioRecords[0].fullAddress('chi')); - - // 1. Best Case: Land result and ogcio return the same address - if (sortedOgcioRecords[0].distanceTo(landRecords[0]) < NEAR_THRESHOLD) { - console.log('1. Best Case: Land result and ogcio return the same address'); - return sortedOgcioRecords; - } - - // 2. best result from OGCIO is not the land result but somehow within the 200 records and we would find it out - // Do 200 * n coordinates calculation - console.log('2. best result from OGCIO is not the land result but somehow within the 200 records and we would find it out'); - console.log('Distance shorter than ' + NEAR_THRESHOLD + ' km'); - sortedOgcioRecords.forEach(ogcioRecord => { - if (ogcioRecord.distanceTo(landRecords[0]) < NEAR_THRESHOLD) { - sortedResults.push(ogcioRecord); - console.log(ogcioRecord.distanceTo(landRecords[0]) + ' | ' + ogcioRecord.fullAddress('chi')) - } - }); - - if (sortedResults.length > 0) { - return sortedResults; - } - - - // 3. ogcio not found but there is land result. We use the record then. - console.log('3. ogcio not found but there is land result.'); - return landRecords; - // TODO: - // in ResultSelector, compare the distance between ogcioData Bestmatch and first result of landResult, - // Assumption: landResult is more accurate, and cover more location of HK - - // tried and got correct result from landResult : - // 政府總部 - // 立法會綜合大樓 - // 寶鄉邨 - // 九龍啟德承啟道28號 - - // If the distance is larger than certain value (i.e. 0.1km), which means there are discrepancies between 2 APIs - // ResultSelector will return landResult, coz we assumpe that landResult is more accurate - - // Then the SingleMatch will return one landResult only, instead of 200 results - // For that particular landResult, only coord, addressZH and nameZH would be shown at this moment - // (Logic of retriving extra address component (Region, Sub District, DCCA etc) would be implmeneted later) - - - } -} \ No newline at end of file diff --git a/web/src/lib/models/address-factory.js b/web/src/lib/models/address-factory.js deleted file mode 100644 index 66054a9..0000000 --- a/web/src/lib/models/address-factory.js +++ /dev/null @@ -1,12 +0,0 @@ -import OGCIOAddress from './ogcio-adress'; -import Address from './address'; -import LandAddress from './land-address'; - -export const createAddress = function (type, record) { - switch (type) { - case 'ogcio': return new OGCIOAddress(record); - case 'land' : return new LandAddress(record); - default: return new Address(record); - } - -} \ No newline at end of file diff --git a/web/src/lib/models/address.js b/web/src/lib/models/address.js deleted file mode 100644 index 3d962d0..0000000 --- a/web/src/lib/models/address.js +++ /dev/null @@ -1,62 +0,0 @@ -import * as turf from "@turf/turf" - -export default class Address { - constructor() { - } - - /** - * Return the detailed components of the parsed address - * each element should be in form of - * { - * translatedLabel: - * key: - * translatedValue: - * } - */ - components(lang) { - return []; - } - - componentLabelForKey(key, lang) { - const component = this.components(lang).find(component => component.key === key); - return component === undefined ? '' : component.translatedLabel; - } - - componentValueForKey(key, lang) { - const component = this.components(lang).find(component => component.key === key); - return component === undefined ? '' : component.translatedValue; - } - - fullAddress(lang) { - return null; - } - - coordinate() { - return { - lat: 0, - lng: 0, - } - } - - coordinates() { - return []; - } - - /** - * Return a normalized confident level from 0 - 10 - */ - confidence() { - return 0; - } - - distanceTo(address) { - const cord1 = turf.point([this.coordinate().lat, this.coordinate().lng]); - const cord2 = turf.point([address.coordinate().lat, address.coordinate().lng]); - - return turf.distance(cord1, cord2, {units: 'kilometers'}); - } -} - -Address.LANG_EN = 'eng'; -Address.LANG_ZH = 'chi'; - diff --git a/web/src/lib/models/land-address.js b/web/src/lib/models/land-address.js deleted file mode 100644 index 12d6eae..0000000 --- a/web/src/lib/models/land-address.js +++ /dev/null @@ -1,67 +0,0 @@ -import Address from './address'; - -export default class LandAddress extends Address{ - constructor(landRecord) { - super(); - this.record = landRecord; - } - - /** - * Return the detailed components of the parsed address - * each element should be in form of - * { - * translatedLabel: - * key: - * translatedValue: - * } - */ - components(lang) { - if (lang === Address.LANG_EN) { - return [{ - translatedValue: this.record.nameEN, - key: name, - translatedLabel: "Name" - }]; - } else if (lang === Address.LANG_ZH) { - return [{ - translatedValue: this.record.nameZH, - key: name, - translatedLabel: "Name" - }]; - } - } - - fullAddress(lang) { - if (lang === Address.LANG_EN) { - return this.record.addressEN; - } else if (lang === Address.LANG_ZH) { - return this.record.addressZH; - } - } - - coordinate() { - return { - lat: this.record.lat, - lng: this.record.lng, - } - } - - coordinates() { - - return [{ - lat: this.record.lat, - lng: this.record.lng, - }]; - } - - /** - * Return a normalized confident level from 0 - 10 - */ - confidence() { - return 0; - } -} - -Address.LANG_EN = 'eng'; -Address.LANG_ZH = 'chi'; - diff --git a/web/src/lib/models/ogcio-adress.js b/web/src/lib/models/ogcio-adress.js deleted file mode 100644 index 0ef7e11..0000000 --- a/web/src/lib/models/ogcio-adress.js +++ /dev/null @@ -1,76 +0,0 @@ -import Address from './address'; -import ogcioHelper from "./../../utils/ogcio-helper.js"; - -export default class OGCIOAddress extends Address { - constructor(ogcioRecord) { - super(); - this.record = ogcioRecord; - this.flattenedComponents = null; - } - - components(lang) { - if (this.flattenedComponents === null) { - this.flattenedComponents = this.flattenComponents(); - } - if (lang === Address.LANG_EN) { - return this.flattenedComponents['eng']; - } else { - return this.flattenedComponents['chi']; - } - } - - flattenComponents() { - const flattenedComponents = { - [Address.LANG_EN]: [], - [Address.LANG_ZH]: [], - }; - const langs = [Address.LANG_ZH, Address.LANG_EN] - for (const lang of langs) { - for (const key of Object.keys(this.record[lang])) { - flattenedComponents[lang].push({ - key, - translatedLabel: ogcioHelper.textForKey(key, lang), - translatedValue: ogcioHelper.textForValue(this.record, key, lang), - }); - } - } - - return flattenedComponents; - } - - fullAddress(lang) { - if (lang === Address.LANG_EN) { - return ogcioHelper.fullChineseAddressFromResult(this.record['eng']); - } else { - return ogcioHelper.fullChineseAddressFromResult(this.record['chi']); - } - } - - coordinate() { - const geo = { - lat: 0, - lng: 0, - }; - if (this.record.geo !== undefined && this.record.geo.length > 0) { - geo.lat = this.record.geo[0].Latitude; - geo.lng = this.record.geo[0].Longitude; - } - return geo; - } - - coordinates() { - return []; - } - - confidence() { - return Math.min( - 4, - (this.record.matches - .filter(match => match.matchedKey === key) - .map(match => match.confident) - .reduce((p, c) => c, 0) * - 5) | - 0 - ); - } -} \ No newline at end of file diff --git a/web/src/pages/AddressSearcher.vue b/web/src/pages/AddressSearcher.vue new file mode 100644 index 0000000..75b06b6 --- /dev/null +++ b/web/src/pages/AddressSearcher.vue @@ -0,0 +1,135 @@ + + + \ No newline at end of file diff --git a/web/src/pages/BatchAddressSearcher.vue b/web/src/pages/BatchAddressSearcher.vue index b4c57e5..7856dec 100644 --- a/web/src/pages/BatchAddressSearcher.vue +++ b/web/src/pages/BatchAddressSearcher.vue @@ -1,6 +1,7 @@