import {ObjectData} from "@novotech/novorender"; import {ObjectInfo} from "types"; import _filter from 'lodash/filter'; import _sumBy from 'lodash/sumBy'; import _sortBy from 'lodash/sortBy'; import {format, parse} from "date-fns"; import _ from "lodash"; export const SCENE_ID_MAIN = 'f72a3bfd88294585be289c87ae6ebcc8'; export const SCENE_ID_BETA = 'cd126a09c0334d5698b50df22af43a58'; export const colorsMMI = [ {mmi: '100', color: [0.859,0.325,0.286]}, {mmi: '200', color: [0.957,0.69,0.573]}, {mmi: '300', color: [0.933,0.522,0.345]}, {mmi: '340', color:[0.98,0.875,0.647]}, {mmi: '350', color:[0.969,0.804,0.455]}, {mmi: '400', color:[0.878,0.882,0.588]}, {mmi: '410', color:[0.812,0.82,0.369]}, {mmi: '430', color:[0.671,0.749,0.588]}, {mmi: '450', color:[0.494,0.616,0.365]}, {mmi: '460', color:[0.545,0.745,0.91]}, {mmi: '480', color:[0.298,0.608,0.859]}, {mmi: '500', color:[0.267,0.392,0.612]}, {mmi: '520', color:[0.902,0.773,0.82]}, {mmi: '530', color:[0.839,0.631,0.71]}, {mmi: '550', color:[0.753,0.431,0.553]}, ] export const mmiMap = new Map() colorsMMI.forEach((m, i) => mmiMap.set(m.mmi, i + 4)) export const searchPattern = { vegbru: {property: "MERKNADER/003 V440Byggverkskategorinavn", value: "Vegbru"}, betong: {property: "MERKNADER/015 V440Materialtype", value: 'Betong'} } export const searchPropertiesName = { volume: 'ePset_SimplebimBasicQuantities/Volume, net (Simplebim)', mmi: 'MERKNADER/012 MMI', kontrakt: 'MERKNADER/021 Kontraktnr', byggelementkode: 'V440/006 V440Byggverkselementkode', elementId: 'MERKNADER/001 ElementID', type: 'MERKNADER/005 V440Byggverkstypenavn', material: 'MERKNADER/015 V440Materialtype', area: '_V770 (06. Identifikasjon modellkomponenter)/ElementsamlingID' } export const jotneDefinedTypes = { volume: 'IFCVOLUMEMEASURE' } export const PropertiesInVisualization: any = { mmi: searchPropertiesName.mmi, kontrakt: searchPropertiesName.kontrakt, byggelementkode: searchPropertiesName.byggelementkode, elementId: searchPropertiesName.elementId } export const setMMIColorOnModel = async (scene: any, view: any) => { const objs: ObjectData[] = [] for await (const obj of scene.search({ descentDepth: 1000, full: true })) { objs.push(await obj.loadMetaData()); } view.settings.selectedObjects.ids = [...objs.map(ob => ob.id)]; for (const obj of objs) { const objRef = scene.getObjectReference(obj.id) const objData = await objRef.loadMetaData(); const MMIProp: any = objData.properties.find((prop: any) => prop.key === searchPropertiesName.mmi); if (MMIProp) { view.settings.selectedObjects.color = colorsMMI[MMIProp['value']] } } } const greenHue = 120; const redHue = 345; export const colorsInVisualization = { green: `hsl(${greenHue}, 85%, 45%)`, red: `hsl(${redHue}, 85%, 45%)`, } export const mapData = (objs: any) => { return objs.map((ob: any) => { const res: any = Object.keys(PropertiesInVisualization).map((key) => { return { [PropertiesInVisualization[key]]: ob.properties.find((prop: any) => prop.key === PropertiesInVisualization[key])?.value } }) return { ...ob, ...Object.assign({}, ...res) } } ) } export const groupBy = (key: string) => { return function group(array: any) { return array.reduce((acc: any, obj: any) => { const property = obj[key]; acc[property] = acc[property] || []; acc[property].push(obj); return acc; }, {}); }; } export const unitTypes = { percent: '%', cubicMeter: 'm3', ton: 'tonn' } export const unitStrings = { percent: '%', cubicMeter: ' m³', ton: ' tonn' } export const createVisualizationData = (statistics: any) => { const visualizationData : any[] = []; statistics.entries.forEach((entry: any, index: number) => { const value = round0(entry.value); if (value !== 0) { let unitString; switch (statistics.unit) { case "PERCENT": unitString = unitStrings.percent; break; case "CUBICMETER": unitString = unitStrings.cubicMeter; break; case "TON": unitString = unitStrings.ton; break; default: unitString = ""; break; } visualizationData.push({ id: `${entry.key}`, //label: `${entry.key}`, value, label: `${value}${unitString}`, color: `hsl(${greenHue - (index * 40)}, 85%, 45%)` }); } }); return _sortBy(visualizationData, (o) => -o.value); } const valueToNumber = (value : string) => { const matched = value.match(/^[\d.][\d.E]*/); if (matched != null) { return +(matched[0]); } else { return 0; } } export const calcTotalVolumeNovotech = (objects : ObjectInfo[]) => { let total = 0; for (const objectInfo of objects) { const volume = objectInfo.properties[searchPropertiesName.volume]; if (volume !== undefined) { total += +(valueToNumber(volume)); } } return total; } // TODO: remove export const calcTotalVolume = (objs: any) => { let total = 0; for (const obj of objs) { for (const prop of obj.properties.filter( (p: any) => p.key === searchPropertiesName.volume )) { const p: any = prop; total += +(valueToNumber(p['value'])); } } return total } export const calcTotalVolumeJotne = (objs: any) => { let total = 0; for (const obj of objs) { for (const prop of obj.properties.filter( (p: any) => p.definedType === jotneDefinedTypes.volume )) { const p: any = prop; total += +(valueToNumber(p.propertyValue)); } } return total; } export const calcTotalCompletedCount = (statistics: any) => { return _sumBy(statistics.mmi.entries, (entry: any) => { if (entry.key >= 500) { return entry.count; } else { return 0; } }); } export const calcTotalCompletedSum = (statistics: any) => { return _sumBy(statistics.mmi.entries, (entry: any) => { if (entry.key >= 500) { return valueToNumber(entry.value); } else { return 0; } }); } export interface ContractInfo { name: string completedPercent: number sum: number } export const extractContractDetails = (statistics: any) => { const contracts: ContractInfo[] = []; _.each(statistics.contract.entries, (entry) => { contracts.push({ name: entry.key, completedPercent: round0((entry.completedCount / entry.count) * 100), sum: round0(entry.value) }); }); return contracts; } export const mapProgressPlanToKeyValue = (progressPlan: any) => { const helpers: any = [] progressPlan?.data?.map((row: any, i: number) => { if (i === 0) return; let obj = {} row.map((col: any, i: number) => { if (i === 3) obj = {...obj, ...{taskName: col}} if (i === 5) obj = {...obj, ...{startDate: col}} if (i === 6) obj = {...obj, ...{endDate: col}} if (i === 9) obj = {...obj, ...{mmi: col}} if (i === 10) obj = {...obj, ...{elementId: col}} }) helpers.push(obj) }) return helpers; } export const filterByMaterial = (objects: ObjectInfo[], material: string) => { return _filter(objects, (objectInfo) => { return objectInfo.properties["MERKNADER/015 V440Materialtype"] === material; }); } export const percentage0 = (value: number) => { return `${round0(value * 100)}%` } export const percentage1 = (value: number) => { return `${(value * 100).toFixed(1)}%` } export const percentage2 = (value: number) => { return `${(value * 100).toFixed(2)}%` } export function formatBillion (labelValue: number, fractionDigits: number = 3, withLabel: boolean = false) { const returnValue = `${round(Math.abs(labelValue) / 1.0e+9, fractionDigits)}` if (withLabel) return `${returnValue} mrd.`; return `${returnValue}`; } export const parseDate = (date: string, format: string = 'EEE dd.MM.yy') => { return new Date(parse(date, format, new Date())).getTime() } export const formatDate = (date: string | null) => { if (date) return format(new Date(date), 'dd.MM.yyyy') else return null } export function round(num: any, fractionDigits: number) { const factor = 10 * fractionDigits || 1; return Math.round(+num + Number.EPSILON * factor) / factor; } export function round0(num: any) { return Math.round(+num + Number.EPSILON); } export function round1(num: any) { return Math.round((+num + Number.EPSILON) * 10) / 10; } export function round2(num: any) { return Math.round((+num + Number.EPSILON) * 100) / 100; }