calcDepthStartEndByConnect.mjs

import each from 'lodash-es/each.js'
import get from 'lodash-es/get.js'
import size from 'lodash-es/size.js'
import join from 'lodash-es/join.js'
import isNumber from 'lodash-es/isNumber.js'
import sortBy from 'lodash-es/sortBy.js'
import cloneDeep from 'lodash-es/cloneDeep.js'
import cdbl from 'wsemi/src/cdbl.mjs'
import isestr from 'wsemi/src/isestr.mjs'
import isearr from 'wsemi/src/isearr.mjs'
import isnum from 'wsemi/src/isnum.mjs'
import judge from './judge.mjs'


/**
 * 調整各樣本起訖深度成為各層互相接續狀態
 *
 * Unit Test: {@link https://github.com/yuda-lyu/w-geo/blob/master/test/calcDepthStartEndByConnect.test.js Github}
 * @memberOf w-geo
 * @param {Array} rows 輸入數據陣列,各數據為物件,至少需包含起始深度(depthStart)與結束深度(depthEnd),深度單位為m
 * @param {Object} [opt={}] 輸入設定物件,預設{}
 * @param {String} [opt.keyDepthStart='depthStart'] 輸入欲儲存之起始深度欄位鍵值字串,預設'depthStart'
 * @param {String} [opt.keyDepthEnd='depthEnd'] 輸入欲儲存之結束深度欄位鍵值字串,預設'depthEnd'
 * @param {Number} [opt.depthEndMax=null] 輸入最大結束深度數字,若最深樣本的結束深度若小於depthEndMax,則自動給予depthEndMax,預設null
 * @returns {Array} 回傳群組化後添加起訖深度與所屬原數據的陣列
 * @example
 *
 * let rows
 * let rs
 *
 * rows = [
 *     {
 *         depthStart: 0,
 *         depthEnd: 4,
 *     },
 *     {
 *         depthStart: 6,
 *         depthEnd: 10,
 *     },
 *     {
 *         depthStart: 11,
 *         depthEnd: 15,
 *     },
 * ]
 * rs = calcDepthStartEndByConnect(rows)
 * console.log(rs)
 * // => [
 * //   { depthStart: 0, depthEnd: 5 },
 * //   { depthStart: 5, depthEnd: 10.5 },
 * //   { depthStart: 10.5, depthEnd: 15 }
 * // ]
 *
 * rows = [
 *     {
 *         depthStart: 0,
 *         depthEnd: 5,
 *     },
 *     {
 *         depthStart: 4,
 *         depthEnd: 15,
 *     },
 * ]
 * try {
 *     rs = calcDepthStartEndByConnect(rows)
 * }
 * catch (err) {
 *     rs = err.toString()
 * }
 * console.log(rs)
 * // => Error: 第 0 樣本之結束深度depthEnd[5]大於第 1 樣本之起點深度depthStart[4]
 *
 * rows = [
 *     {
 *         depthStart: '0',
 *         depthEnd: '4',
 *     },
 *     {
 *         depthStart: '6',
 *         depthEnd: '10',
 *     },
 * ]
 * rs = calcDepthStartEndByConnect(rows)
 * console.log(rs)
 * // => [ { depthStart: '0', depthEnd: 5 }, { depthStart: 5, depthEnd: '10' } ]
 *
 * rows = [
 *     {
 *         depthStart: '0',
 *         depthEnd: 'abc',
 *     },
 *     {
 *         depthStart: 'abc',
 *         depthEnd: '10',
 *     },
 * ]
 * try {
 *     rs = calcDepthStartEndByConnect(rows)
 * }
 * catch (err) {
 *     rs = err.toString()
 * }
 * console.log(rs)
 * // => Error: 第 0 樣本結束深度depthEnd[abc]非有效數字, 第 1 樣本起始深度depthStart[abc]非有效數字
 *
 * rows = [
 *     {
 *         top_depth: 0,
 *         bottom_depth: 4,
 *     },
 *     {
 *         top_depth: 6,
 *         bottom_depth: 10,
 *     },
 * ]
 * rs = calcDepthStartEndByConnect(rows, { keyDepthStart: 'top_depth', keyDepthEnd: 'bottom_depth' })
 * console.log(rs)
 * // => [
 * //   { top_depth: 0, bottom_depth: 5 },
 * //   { top_depth: 5, bottom_depth: 10 }
 * // ]
 *
 * rows = [
 *     {
 *         depthStart: 0,
 *         depthEnd: 4,
 *     },
 *     {
 *         depthStart: 6,
 *         depthEnd: 10,
 *     },
 *     {
 *         depthStart: 11,
 *         depthEnd: 15,
 *     },
 * ]
 * rs = calcDepthStartEndByConnect(rows, { depthEndMax: 20 })
 * console.log(rs)
 * // => [
 * //   { depthStart: 0, depthEnd: 5 },
 * //   { depthStart: 5, depthEnd: 10.5 },
 * //   { depthStart: 10.5, depthEnd: 20 }
 * // ]
 *
 */
function calcDepthStartEndByConnect(rows, opt = {}) {
    let errs = []

    //check
    if (!isearr(rows)) {
        throw new Error('無有效資料')
    }

    //keyDepthStart
    let keyDepthStart = get(opt, 'keyDepthStart')
    if (!isestr(keyDepthStart)) {
        keyDepthStart = 'depthStart'
    }

    //keyDepthEnd
    let keyDepthEnd = get(opt, 'keyDepthEnd')
    if (!isestr(keyDepthEnd)) {
        keyDepthEnd = 'depthEnd'
    }

    //depthEndMax
    let depthEndMax = get(opt, 'depthEndMax')
    if (isnum(depthEndMax)) {
        depthEndMax = cdbl(depthEndMax)
    }
    else {
        depthEndMax = null
    }

    //cloneDeep
    rows = cloneDeep(rows)

    //判斷各樣本起訖深度需為有效數字
    each(rows, (v, k) => {

        //ds, de
        let ds = get(v, keyDepthStart, null)
        let de = get(v, keyDepthEnd, null)

        //check
        if (!isnum(ds)) {
            errs.push(`第 ${k} 樣本起始深度${keyDepthStart}[${ds}]非有效數字`)
        }
        if (!isnum(de)) {
            errs.push(`第 ${k} 樣本結束深度${keyDepthEnd}[${de}]非有效數字`)
        }

    })

    //check
    if (size(errs) > 0) {
        throw new Error(join(errs, ', '))
    }

    //sortBy
    rows = sortBy(rows, (v) => {
        return cdbl(v[keyDepthStart])
    })

    //判斷上層樣本結束深度不得大於下層樣本起始深度
    each(rows, (v, k) => {
        if (k === 0) {
            return true
        }

        //de0, ds1
        let de0 = get(rows, `${k - 1}.${keyDepthEnd}`, null)
        let ds1 = get(v, keyDepthStart, null)
        de0 = cdbl(de0)
        ds1 = cdbl(ds1)

        //check
        if (judge(de0, '>', ds1)) {
            errs.push(`第 ${k - 1} 樣本之結束深度${keyDepthEnd}[${de0}]大於第 ${k} 樣本之起點深度${keyDepthStart}[${ds1}]`)
        }

    })

    //check
    if (size(errs) > 0) {
        throw new Error(join(errs, ', '))
    }

    //each
    each(rows, (v, k) => {
        if (k === 0) {
            return true
        }

        //de0, ds1
        let de0 = get(rows, `${k - 1}.${keyDepthEnd}`, null)
        let ds1 = get(v, keyDepthStart, null)
        de0 = cdbl(de0)
        ds1 = cdbl(ds1)

        //check
        if (judge(de0, '<', ds1)) {
            let dc = (de0 + ds1) / 2
            rows[k - 1][keyDepthEnd] = dc
            rows[k + 0][keyDepthStart] = dc
        }

    })

    //depthEndMax
    if (isNumber(depthEndMax)) {
        let up = size(rows) - 1
        let rowsEnd = rows[up]
        let de = rowsEnd[keyDepthEnd]
        if (judge(de, '<', depthEndMax)) {
            rows[up][keyDepthEnd] = depthEndMax
        }
    }

    return rows
}


export default calcDepthStartEndByConnect