smoothDepthByKey.mjs

import get from 'lodash-es/get.js'
import each from 'lodash-es/each.js'
import map from 'lodash-es/map.js'
import size from 'lodash-es/size.js'
import sortBy from 'lodash-es/sortBy.js'
import arrAt from 'wsemi/src/arrAt.mjs'
import cdbl from 'wsemi/src/cdbl.mjs'
import cint from 'wsemi/src/cint.mjs'
import isnum from 'wsemi/src/isnum.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import isp0int from 'wsemi/src/isp0int.mjs'
import arrAverage from 'w-statistic/src/arrAverage.mjs'
import arrStd from 'w-statistic/src/arrStd.mjs'
import arrCount from 'w-statistic/src/arrCount.mjs'


/**
 * 平滑化含深度與指定欄位之樣本陣列
 *
 * Unit Test: {@link https://github.com/yuda-lyu/w-geo/blob/master/test/calcDepthStartEndByConnect.test.js Github}
 * @memberOf w-geo
 * @param {Array} rows 輸入物件陣列
 * @param {String} key 輸入欲平滑之欄位鍵名稱字串
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {String} [opt.keyDepth='depth'] 輸入深度欄位鍵名稱字串,預設'depth'
 * @param {String} [opt.methodSmooth='average'] 輸入平滑化方法字串,可選'average'、'averageIn95'、'maxCount',預設'average'
 * @param {Object} [opt.ranger={}] 輸入提取窗形方式之設定物件,預設{}
 * @param {Intger} [opt.ranger.countHalf=5] 輸入提取上下點數整數,例如給予5代表上下取5點加自己共11點,預設5
 * @param {Number} [opt.ranger.depthHalf=0.25] 輸入提取上下距離數字,單位m,例如給予0.25代表上下取0.25m共0.5m,預設0.25
 * @returns {Array} 回傳平滑化後陣列
 * @example
 * 待補充
 */
function smoothDepthByKey(rows, key, opt = {}) {

    //check
    if (size(rows) === 0) {
        return []
    }
    if (!isestr(key)) {
        return []
    }

    //countHalf
    let countHalf = get(opt, 'ranger.countHalf')
    if (!isp0int(countHalf)) {
        countHalf = 5 //上下取5點加自己共11點
    }
    countHalf = cint(countHalf)

    //depthHalf
    let depthHalf = get(opt, 'ranger.depthHalf')
    if (!isnum(depthHalf)) {
        depthHalf = 0.25 //上下取0.25m共0.5m
    }
    depthHalf = cdbl(depthHalf)

    //keyDepth
    let keyDepth = get(opt, 'keyDepth')
    if (!isestr(keyDepth)) {
        keyDepth = 'depth'
    }

    //methodSmooth
    let methodSmooth = get(opt, 'methodSmooth')
    if (methodSmooth !== 'average' && methodSmooth !== 'averageIn95' && methodSmooth !== 'maxCount') {
        methodSmooth = 'average'
    }

    //ltdtEff
    let ltdtEff = []
    each(rows, (v) => {
        let d = get(v, keyDepth)
        let r = get(v, key)
        if (isnum(d) && (isestr(r) || isnum(r))) { //key值允許字串或數字
            v[keyDepth] = cdbl(d)
            v[key] = r
            ltdtEff.push(v)
        }
    })

    //check
    if (size(ltdtEff) === 0) {
        return []
    }

    //sortBy
    ltdtEff = sortBy(ltdtEff, keyDepth)

    //up
    let up = size(ltdtEff) - 1

    //rs
    let rs = []
    each(ltdtEff, (v, k) => {

        //ks, ke
        let ks = k
        let ke = k
        if (countHalf !== null) {
            ks = Math.max(k - countHalf, 0)
            ke = Math.min(k + countHalf, up)
        }
        else if (depthHalf !== null) {

            //calc ks
            for (let i = k; i >= 0; i--) {
                let depthDiff = Math.abs(ltdtEff[i][keyDepth] - v[keyDepth])
                if (depthDiff < depthHalf) {
                    ks = i
                }
                else {
                    break
                }
            }

            //calc ke
            for (let i = k; i <= up; i++) {
                let depthDiff = Math.abs(ltdtEff[i][keyDepth] - v[keyDepth])
                if (depthDiff < depthHalf) {
                    ke = i
                }
                else {
                    break
                }
            }

        }

        //arrAt
        let ltdtTemp = arrAt(ltdtEff, ks, ke)

        //p
        let p = null
        if (methodSmooth === 'average') {

            //arr
            let arr = map(ltdtTemp, key)

            //arrAverage
            let avg = arrAverage(arr)

            //save
            p = {
                [key]: avg,
            }

        }
        else if (methodSmooth === 'averageIn95') {

            //arr
            let arr = map(ltdtTemp, key)

            //arrAverage
            let a = arrAverage(arr)

            //arrStd
            let s = arrStd(arr)

            //ts
            let _ts = []
            let ts = []
            each(ltdtTemp, (v) => {
                let t = get(v, key)
                if (isnum(t)) {
                    t = cdbl(t)
                    _ts.push(t)
                    if (t >= a - 2 * s && t <= a + 2 * s) {
                        ts.push(t) //介於平均值2倍標準差內數字才儲存
                    }
                }
            })
            // console.log('_ts', _ts)
            // console.log('ts', ts)

            //avg
            let avg = arrAverage(ts)
            // console.log('avg', avg)

            //save
            p = {
                [key]: avg,
            }

        }
        else if (methodSmooth === 'maxCount') {

            //arr
            let arr = map(ltdtTemp, key)

            //arrCount
            let q = arrCount(arr)

            //取第1個的key, 也就是最多的
            let rk = get(q, `0.key`, '')
            let rc = get(q, `0.count`, '')

            //save
            p = {
                [key]: rk,
                count: rc,
            }

        }

        //s
        let s = {
            ...v,
            ...p,
        }

        //push
        rs.push(s)

    })

    return rs
}


export default smoothDepthByKey