import get from 'lodash-es/get.js'
import size from 'lodash-es/size.js'
import isearr from 'wsemi/src/isearr.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import isnum from 'wsemi/src/isnum.mjs'
import ispint from 'wsemi/src/ispint.mjs'
import isbol from 'wsemi/src/isbol.mjs'
import ispm from 'wsemi/src/ispm.mjs'
import isfun from 'wsemi/src/isfun.mjs'
import cdbl from 'wsemi/src/cdbl.mjs'
import cint from 'wsemi/src/cint.mjs'
import pmSeries from 'wsemi/src/pmSeries.mjs'
import _kriging from './interp2Kriging.mjs'
/**
* 不規則點內插至規則網格
*
* Unit Test: {@link https://github.com/yuda-lyu/w-gis/blob/master/test/interp2Grid.test.mjs Github}
* @memberOf w-gis
* @param {Array} pts 輸入二維座標加觀測數據點陣列,為[{x:x1,y:y1,z:z1},{x:x2,y:y2,z:z2},...]點物件之陣列
* @param {Number} xmin 輸入網格x向最小座標數字
* @param {Number} xmax 輸入網格x向最大座標數字
* @param {Number} dx 輸入網格x向間距數字
* @param {Number} ymin 輸入網格y向最小座標數字
* @param {Number} ymax 輸入網格y向最大座標數字
* @param {Number} dy 輸入網格y向間距數字
* @param {Object} [opt={}] 輸入設定物件,預設{}
* @param {String} [opt.keyX='x'] 輸入點物件之x座標欄位字串,預設'x'
* @param {String} [opt.keyY='y'] 輸入點物件之y座標欄位字串,預設'y'
* @param {String} [opt.keyZ='z'] 輸入點物件之z座標或值欄位字串,預設'z'
* @param {String} [opt.modePick='min'] 輸入挑選方式字串,可選'min'、'max',預設'min'
* @param {Function} [opt.funValid=(x,y)=>{return true}] 輸入確認點座標(x,y)是否有效函數,回傳布林值,可使用Promise回傳,預設(x,y)=>{return true}
* @param {Function} [opt.funKriging=interp2Kriging] 輸入克利金處理函數,預設使用內建interp2Kriging
* @param {String} [opt.variogram_model='spherical'] 輸入內建interp2Kriging之變異函數模型字串,預設'spherical'
* @param {Number} [opt.nlags=9] 輸入內建interp2Kriging之分箱數量整數,預設9
* @param {Function} [opt.funAdjust=(x,y,z)=>{return z}] 輸入內插後值調整函數,用於修正不合理值或做後處理,回傳布林值,可使用Promise回傳,預設(x,y,z)=>{return z}
* @param {Boolean} [opt.returnGrid=true] 輸入是否回傳規則網格物件布林值,若false則回傳內插後點物件陣列,預設true
* @param {Boolean} [opt.inverseKeyY=false] 輸入是否反轉y方向索引布林值,用於輸出grds之y向(列)順序,預設false
* @returns {Object} 回傳規則網格物件,物件內grds為規則網格之二維陣列
* @example
*
* let ps
* let r
* let xmin = 0
* let xmax = 1200
* let dx = 100
* let ymin = 0
* let ymax = 400
* let dy = 50
*
* ps = [{ x: 243, y: 206, z: 95 }, { x: 233, y: 225, z: 146 }, { x: 21, y: 325, z: 22 }, { x: 953, y: 28, z: 223 }, { x: 1092, y: 290, z: 39 }, { x: 744, y: 200, z: 191 }, { x: 174, y: 3, z: 22 }, { x: 537, y: 368, z: 249 }, { x: 1151, y: 371, z: 86 }, { x: 814, y: 252, z: 125 }]
* r = await interp2Grid(ps, xmin, xmax, dx, ymin, ymax, dy)
* console.log(JSON.stringify(r))
* // => {"xnum":13,"xmin":0,"xmax":1200,"dx":100,"ynum":9,"ymin":0,"ymax":400,"dy":50,"zmin":27.716420638718002,"zmax":229.9346471582616,"grds":[[44.75150359539468,33.373113045618794,33.89828595915838,75.7547049098998,111.95710473149644,141.14982654621605,162.94590093717213,178.58593009365336,191.4829386115651,208.81802511395395,199.48735656973935,162.30106522787239,139.5822916387848],[43.27848738559962,36.56178372212405,43.70097267468331,81.3441145925311,118.98473675109194,149.02943152384705,170.11407784661236,183.17995238983585,190.7561365867844,203.31673250583682,190.93888531046233,152.18106412879206,131.13037328401273],[43.188448792811485,44.651404666899325,58.49967415560389,90.7364184599852,128.7782694260302,158.79276063034376,178.11277546086842,187.40687634934446,185.3791304293,183.41945619591084,166.72664102123193,135.5945265305882,119.75833215759124],[43.01723687928732,53.80526318172193,74.78037419059014,102.8093108917395,141.2308220822185,170.46799156406368,186.77594170674791,191.60033532320656,175.79675777808637,159.46469201580493,139.126174723786,114.04299018304454,106.38160257786299],[41.08480660653146,61.698862792555914,100.50549432728168,120.40751273285129,155.77538965247686,183.9818177781901,195.76812296601497,193.3040612514098,159.6797783607955,136.06558026941212,112.82889049769918,89.27300522673185,92.85373380938937],[35.96748845888605,65.74413088706496,124.5372066072104,142.93975356224172,170.6014830855453,199.17487480394007,205.0642462793919,187.868001472236,136.21583771497808,117.90972253067659,91.6262819436449,62.41761369022669,82.44922512861154],[27.716420638718002,66.37302553896835,123.09560307481105,153.9089017619669,182.78671416843497,215.58411971399806,214.7143054081681,183.4416893350021,136.16098981693074,109.45391646724518,80.86241021849614,45.287458404590105,79.54913115775582],[31.84799135435849,69.51355338700839,120.62450343623689,156.78399055536207,189.72044252659893,229.9346471582616,221.71844479339634,181.54689685389988,139.24108529554456,108.74457142842628,81.95639661703339,66.50915956750916,84.78931182091034],[48.714341720984095,77.18149833637362,120.04944872983206,156.36419684697117,190.18663173864468,226.80390649899172,218.0338522947777,179.1554914349331,141.35776216308057,111.63930150324168,88.90310614105951,81.63042177986947,90.77494563964606]]}
*
* ps = [{ a: 243, b: 206, c: 95 }, { a: 233, b: 225, c: 146 }, { a: 21, b: 325, c: 22 }, { a: 953, b: 28, c: 223 }, { a: 1092, b: 290, c: 39 }, { a: 744, b: 200, c: 191 }, { a: 174, b: 3, c: 22 }, { a: 537, b: 368, c: 249 }, { a: 1151, b: 371, c: 86 }, { a: 814, b: 252, c: 125 }]
* r = await interp2Grid(ps, xmin, xmax, dx, ymin, ymax, dy, { keyX: 'a', keyY: 'b', keyZ: 'c' })
* console.log(JSON.stringify(r))
* // => {"xnum":13,"xmin":0,"xmax":1200,"dx":100,"ynum":9,"ymin":0,"ymax":400,"dy":50,"zmin":27.716420638718002,"zmax":229.9346471582616,"grds":[[44.75150359539468,33.373113045618794,33.89828595915838,75.7547049098998,111.95710473149644,141.14982654621605,162.94590093717213,178.58593009365336,191.4829386115651,208.81802511395395,199.48735656973935,162.30106522787239,139.5822916387848],[43.27848738559962,36.56178372212405,43.70097267468331,81.3441145925311,118.98473675109194,149.02943152384705,170.11407784661236,183.17995238983585,190.7561365867844,203.31673250583682,190.93888531046233,152.18106412879206,131.13037328401273],[43.188448792811485,44.651404666899325,58.49967415560389,90.7364184599852,128.7782694260302,158.79276063034376,178.11277546086842,187.40687634934446,185.3791304293,183.41945619591084,166.72664102123193,135.5945265305882,119.75833215759124],[43.01723687928732,53.80526318172193,74.78037419059014,102.8093108917395,141.2308220822185,170.46799156406368,186.77594170674791,191.60033532320656,175.79675777808637,159.46469201580493,139.126174723786,114.04299018304454,106.38160257786299],[41.08480660653146,61.698862792555914,100.50549432728168,120.40751273285129,155.77538965247686,183.9818177781901,195.76812296601497,193.3040612514098,159.6797783607955,136.06558026941212,112.82889049769918,89.27300522673185,92.85373380938937],[35.96748845888605,65.74413088706496,124.5372066072104,142.93975356224172,170.6014830855453,199.17487480394007,205.0642462793919,187.868001472236,136.21583771497808,117.90972253067659,91.6262819436449,62.41761369022669,82.44922512861154],[27.716420638718002,66.37302553896835,123.09560307481105,153.9089017619669,182.78671416843497,215.58411971399806,214.7143054081681,183.4416893350021,136.16098981693074,109.45391646724518,80.86241021849614,45.287458404590105,79.54913115775582],[31.84799135435849,69.51355338700839,120.62450343623689,156.78399055536207,189.72044252659893,229.9346471582616,221.71844479339634,181.54689685389988,139.24108529554456,108.74457142842628,81.95639661703339,66.50915956750916,84.78931182091034],[48.714341720984095,77.18149833637362,120.04944872983206,156.36419684697117,190.18663173864468,226.80390649899172,218.0338522947777,179.1554914349331,141.35776216308057,111.63930150324168,88.90310614105951,81.63042177986947,90.77494563964606]]}
*
* ps = [{ x: 243, y: 206, z: 95 }, { x: 233, y: 225, z: 146 }, { x: 21, y: 325, z: 22 }, { x: 953, y: 28, z: 223 }, { x: 1092, y: 290, z: 39 }, { x: 744, y: 200, z: 191 }, { x: 174, y: 3, z: 22 }, { x: 537, y: 368, z: 249 }, { x: 1151, y: 371, z: 86 }, { x: 814, y: 252, z: 125 }]
* r = await interp2Grid(ps, xmin, xmax, dx, ymin, ymax, dy, { scale: 1000 })
* console.log(JSON.stringify(r))
* // => {"xnum":13,"xmin":0,"xmax":1200,"dx":100,"ynum":9,"ymin":0,"ymax":400,"dy":50,"zmin":27.716420638719953,"zmax":229.93464715826363,"grds":[[44.75150359539723,33.3731130456213,33.898285959160816,75.75470490990179,111.95710473149887,141.1498265462182,162.9459009371747,178.5859300936557,191.48293861156722,208.81802511395625,199.48735656974148,162.3010652278742,139.58229163878707],[43.278487385601736,36.56178372212586,43.70097267468564,81.34411459253306,118.98473675109445,149.02943152384924,170.1140778466147,183.179952389838,190.7561365867865,203.31673250583924,190.93888531046477,152.18106412879473,131.1303732840151],[43.188448792813944,44.65140466690163,58.49967415560579,90.73641845998743,128.7782694260323,158.79276063034584,178.11277546087098,187.40687634934702,185.37913042930217,183.4194561959133,166.72664102123443,135.5945265305907,119.75833215759324],[43.01723687928934,53.805263181724015,74.78037419059208,102.80931089174139,141.2308220822208,170.46799156406598,186.77594170674982,191.60033532320872,175.79675777808842,159.46469201580726,139.1261747237881,114.04299018304688,106.38160257786514],[41.08480660653358,61.698862792557975,100.50549432728357,120.4075127328534,155.7753896524789,183.98181777819244,195.76812296601736,193.304061251412,159.6797783607982,136.06558026941445,112.82889049770114,89.27300522673426,92.8537338093916],[35.967488458888354,65.74413088706663,124.53720660721237,142.9397535622437,170.60148308554733,199.17487480394269,205.06424627939438,187.86800147223812,136.21583771498067,117.90972253067889,91.6262819436468,62.417613690228954,82.44922512861409],[27.716420638719953,66.37302553897003,123.09560307481306,153.90890176196856,182.78671416843704,215.5841197140003,214.71430540817065,183.44168933500427,136.1609898169329,109.45391646724778,80.8624102184981,45.28745840459231,79.54913115775784],[31.847991354360566,69.51355338701046,120.62450343623853,156.78399055536397,189.72044252660112,229.93464715826363,221.71844479339836,181.5468968539019,139.24108529554678,108.74457142842883,81.95639661703564,66.50915956751138,84.78931182091229],[48.71434172098658,77.18149833637538,120.04944872983332,156.36419684697321,190.18663173864695,226.8039064989942,218.03385229477985,179.15549143493547,141.35776216308315,111.63930150324393,88.90310614106163,81.63042177987194,90.7749456396484]]}
*
* ps = [{ x: 243, y: 206, z: 95 }, { x: 233, y: 225, z: 146 }, { x: 21, y: 325, z: 22 }, { x: 953, y: 28, z: 223 }, { x: 1092, y: 290, z: 39 }, { x: 744, y: 200, z: 191 }, { x: 174, y: 3, z: 22 }, { x: 537, y: 368, z: 249 }, { x: 1151, y: 371, z: 86 }, { x: 814, y: 252, z: 125 }]
* r = await interp2Grid(ps, xmin, xmax, dx, ymin, ymax, dy, { model: 'gaussian' })
* console.log(JSON.stringify(r))
* // => {"xnum":13,"xmin":0,"xmax":1200,"dx":100,"ynum":9,"ymin":0,"ymax":400,"dy":50,"zmin":-384.9201026300543,"zmax":751.2486667428893,"grds":[[158.4482759179864,102.91948079701615,0.6427517504198477,-76.00797355886607,-68.61483684207815,36.665182208944316,199.83602440246614,345.00056213926655,396.5981895665918,315.1995415714464,114.98419154713338,-144.3509008078363,-384.9201026300543],[-2.804444662458991,-2.4952083123462216,-60.97934153869028,-111.66170902352133,-96.02852249400712,5.207837377654869,160.5808502566615,302.76790555566186,362.1489304061961,301.11674822207897,131.5364918945761,-92.16170607212916,-298.50266437656865],[-118.93900065626804,-56.340223227791284,-68.73471627734216,-96.72954345654944,-81.85939091966793,2.020786152976143,134.65918081245218,260.47611794230215,318.44862005717914,274.1365497524548,136.8288381582006,-45.894921513683585,-211.18795045322622],[-186.25795259313963,-57.13678728956256,-22.92129248260062,-32.59210483370771,-27.8351209619359,25.59859956942455,121.05320514790401,217.5277153486495,264.99722601877875,233.4224463794908,129.30048060534682,-8.057124315122564,-126.42995914376297],[-204.6982411436402,-7.390837633351111,72.13154973463315,75.65547666719249,61.266778354751295,72.2993374763264,117.60932224509997,173.09761839135172,201.734808129484,178.928047108584,108.22019594248195,19.480190656797276,-47.36329745889998],[-177.70454124452772,86.69644962914026,208.46936428354638,219.66178929024136,178.06125662916565,136.71746638113837,121.3145643337175,126.31575766424248,129.1573951962073,111.48613425033363,73.78789676929591,35.622695265119546,23.390294461762096],[-111.78240342620666,215.85784505185075,375.2536623066626,388.57921593784704,313.24173519090436,212.2249882690594,128.66033199911908,76.46368709732087,48.391715239609766,32.82513522314184,27.15561605971925,40.124916167271294,83.86576457299452],[-15.788129694388772,368.6553909168142,559.7541046391179,570.0412080583301,456.43269708112166,291.61788155091926,136.04813556018962,23.157013756701417,-38.78597402585001,-54.49378940718998,-29.636587407456318,33.58501755302677,132.8379551795224],[99.95941993298584,532.539599799884,748.4812810539061,751.2486667428893,597.1137915874442,367.79370328149344,140.18765012677795,-33.51285171881864,-129.99549037223733,-147.21704968592712,-93.80481946551481,17.364755515549405,169.84006648967988]]}
*
* ps = [{ x: 243, y: 206, z: 95 }, { x: 233, y: 225, z: 146 }, { x: 21, y: 325, z: 22 }, { x: 953, y: 28, z: 223 }, { x: 1092, y: 290, z: 39 }, { x: 744, y: 200, z: 191 }, { x: 174, y: 3, z: 22 }, { x: 537, y: 368, z: 249 }, { x: 1151, y: 371, z: 86 }, { x: 814, y: 252, z: 125 }]
* r = await interp2Grid(ps, xmin, xmax, dx, ymin, ymax, dy, { sigma2: 0.001, alpha: 70 })
* console.log(JSON.stringify(r))
* // => {"xnum":13,"xmin":0,"xmax":1200,"dx":100,"ynum":9,"ymin":0,"ymax":400,"dy":50,"zmin":26.701776096728345,"zmax":231.16722254290013,"grds":[[44.11259991617855,32.58450881510232,32.76678140889048,74.2917476479156,110.8906140074769,140.71177964055232,163.06616115295472,179.11502822658102,192.29078928968042,209.95815571466474,200.55109691937588,162.85705779717352,139.89170721934147],[42.61820720122279,35.71041576002229,42.20317945504952,79.46948139766397,117.76066932315202,148.59606792401644,170.29707464354252,183.76349937447452,191.5061647507026,204.2911682442632,191.7981952284658,152.53751223841732,131.30395530835756],[42.539549140517906,43.8682532885825,56.67719512603222,88.39339544912986,127.49833508140833,158.44006523651268,178.39437462529554,188.06459836041196,185.98874971121745,183.9624064738573,167.1064571105411,135.6435755796063,119.76026775033723],[42.40373922516747,53.363687192570794,73.04828246858823,100.13694358752468,140.12379463484046,170.29909587800478,187.1850067213191,192.35842981670092,176.16886158624536,159.48169146034536,138.9684068006453,113.70615799956849,106.20087092877779],[40.475947890621654,61.84636782352866,100.87164130491789,118.51969471321917,155.17367785922463,184.10530910814234,196.31283310410095,194.0800848116069,159.58692053597147,135.55390133035564,112.17296618268094,88.50580626168168,92.52730118195944],[35.241030309738626,66.37032301391976,127.92631718109324,143.48034347842253,170.73957790937519,199.67024834314628,205.7419513911939,188.38823643531202,135.36768638962553,117.01563653626947,90.61097302023494,61.19704954557336,82.09912411624504],[26.701776096728345,67.08365868969182,126.02587930956292,155.6532451767952,183.60847488953968,216.47538395931667,215.53334174966398,183.76978391699137,135.4260482049657,108.47833203695497,79.76360673569025,43.90263898577459,79.40538262088131],[30.87691293677275,70.13688477331618,122.88731890916635,158.7167710050036,190.97418094947915,231.16722254290013,222.66784391843683,181.84273299017318,138.739345167688,107.91389402110133,81.0648238841768,65.98340433363867,85.04412844530214],[48.14919037640777,77.76315260022243,121.8147111056278,158.17170146686848,191.6135973149057,228.14610013364904,219.01737089705114,179.49014246253026,141.06205182632874,111.03450527633353,88.31839228901936,81.59594088565929,91.24372341789248]]}
*
*/
async function interp2Grid(pts, xmin, xmax, dx, ymin, ymax, dy, opt = {}) {
//check
if (!isearr(pts)) {
throw new Error(`no pts`)
}
//check xmin
if (!isnum(xmin)) {
throw new Error(`xmin[${xmin}] is not an effective number`)
}
xmin = cdbl(xmin)
//check xmax
if (!isnum(xmax)) {
throw new Error(`xmax[${xmax}] is not an effective number`)
}
xmax = cdbl(xmax)
//check dx
if (!isnum(dx)) {
throw new Error(`dx[${dx}] is not an effective number`)
}
dx = cdbl(dx)
//check xmin>xmax
if (xmin > xmax) {
throw new Error(`xmin[${xmin}]>xmax[${xmax}]`)
}
//check ymin
if (!isnum(ymin)) {
throw new Error(`ymin[${ymin}] is not an effective number`)
}
ymin = cdbl(ymin)
//check ymax
if (!isnum(ymax)) {
throw new Error(`ymax[${ymax}] is not an effective number`)
}
ymax = cdbl(ymax)
//check dy
if (!isnum(dy)) {
throw new Error(`dy[${dy}] is not an effective number`)
}
dy = cdbl(dy)
//check ymin>ymax
if (ymin > ymax) {
throw new Error(`ymin[${ymin}]>ymax[${ymax}]`)
}
//keyX
let keyX = get(opt, 'keyX')
if (!isestr(keyX)) {
keyX = 'x'
}
//keyY
let keyY = get(opt, 'keyY')
if (!isestr(keyY)) {
keyY = 'y'
}
//keyZ
let keyZ = get(opt, 'keyZ')
if (!isestr(keyZ)) {
keyZ = 'z'
}
//funValid
let funValid = get(opt, 'funValid')
if (!isfun(funValid)) {
funValid = () => {
return true
}
}
//funKriging
let funKriging = get(opt, 'funKriging')
if (!isfun(funKriging)) {
funKriging = _kriging
}
//variogram_model
let variogram_model = get(opt, 'variogram_model')
if (!isestr(variogram_model)) {
variogram_model = 'spherical'
}
//nlags
let nlags = get(opt, 'nlags')
if (!ispint(nlags)) {
nlags = 9
}
nlags = cint(nlags)
//funAdjust
let funAdjust = get(opt, 'funAdjust')
if (!isfun(funAdjust)) {
funAdjust = (x, y, z) => {
return z
}
}
//returnGrid
let returnGrid = get(opt, 'returnGrid')
if (!isbol(returnGrid)) {
returnGrid = true
}
//inverseKeyY
let inverseKeyY = get(opt, 'inverseKeyY')
if (!isbol(inverseKeyY)) {
inverseKeyY = false
}
//xnum
let xnum = 0
for (let x = xmin; x <= xmax; x += dx) {
xnum++
}
//ynum
let ynum = 0
for (let y = ymin; y <= ymax; y += dy) {
ynum++
}
//vpts
let vpts = []
let kpInx = {}
let k = -1
let ix = -1
for (let x = xmin; x <= xmax; x += dx) {
ix++
let iy = -1
for (let y = ymin; y <= ymax; y += dy) {
iy++
k++
//funValid
let b = funValid(x, y)
if (ispm(b)) {
b = await b
}
//check
if (!b) {
continue
}
//push
vpts.push({
[keyX]: x,
[keyY]: y,
[keyZ]: '',
})
//save
kpInx[`${ix}:${iy}`] = k
}
}
// console.log('rs', rs)
//check
if (size(vpts) === 0) {
console.log(xmin, xmax, dx, ymin, ymax, dy)
throw new Error(`no vpts`)
}
//funKriging
let ipts = await funKriging(pts, vpts, {
keyX,
keyY,
keyZ,
...opt,
//interp2Kriging設定參數
// scale,
// model,
// sigma2,
// alpha,
//WKriging設定參數
// variogram_model,
// nlags,
})
//調整不合理值
ipts = await pmSeries(ipts, async (m) => {
// console.log('m', m)
//funAdjust
let z = funAdjust(m[keyX], m[keyY], m[keyZ])
if (ispm(z)) {
z = await z
}
//update
m[keyZ] = z
return m
})
// console.log('ipts(adjust)', ipts)
//returnGrid
let rs = null
if (!returnGrid) {
rs = ipts
}
else {
let grds = []
let zmin = 1e20
let zmax = -1e20
for (let iy = 0; iy < ynum; iy++) {
grds[iy] = []
let _iy = iy
if (inverseKeyY) {
_iy = ynum - 1 - iy
}
for (let ix = 0; ix < xnum; ix++) {
let k = kpInx[`${ix}:${_iy}`]
grds[iy][ix] = ipts[k][keyZ]
zmin = Math.min(zmin, ipts[k][keyZ])
zmax = Math.max(zmax, ipts[k][keyZ])
}
}
rs = {
xnum,
xmin,
xmax,
dx,
ynum,
ymin,
ymax,
dy,
zmin,
zmax,
grds,
}
}
return rs
}
export default interp2Grid