import Frame from '../../data/Frame'; function calculateFrameElevation(frames: Frame[], tokenCountForEachLine: number[]):{elevationForEachFrame:number[],elevationsForEachLine:number[]} { // total number of tokens const tokenCount = tokenCountForEachLine.reduce((sum, x)=>sum+x,0); const elevationTable = initElevationTable(tokenCount); const elevationForEachFrame: number[] = []; const elevationsForEachLine: number[] = []; for(const frame of frames) { let elevation = 0; while(!canFitIntoElevation(elevationTable,frame,elevation)) {elevation++;} fitIntoElevation(elevationTable, frame, elevation); elevationForEachFrame.push(elevation); } let visitedTokenCount = 0; for(const tokenCount of tokenCountForEachLine) { elevationsForEachLine.push( getElevationsWithinSpan(elevationTable, visitedTokenCount, visitedTokenCount+tokenCount)); visitedTokenCount += tokenCount; } return {elevationForEachFrame, elevationsForEachLine}; } function initElevationTable(tokenCount: number):boolean[][] { return [Array(tokenCount).fill(false)]; } function canFitIntoElevation(elevationTable: boolean[][], frame: Frame, elevation: number): boolean { if (elevationTable.length <= elevation) { growElevationTableTo(elevationTable, elevation); return true; } if(frame.roles.length<=0) return true; const [beginTokenIndex, endTokenIndex] = Frame.getTokenSpan(frame); for (let iToken = beginTokenIndex; iToken < endTokenIndex; iToken++) { if (elevationTable[elevation][iToken]) { return false; } } return true; } // fit the frame into a given elevation. update elevation table and set the "elevation" field of the frame. function fitIntoElevation(elevationTable: boolean[][], frame: Frame, elevation: number):void { if(frame.roles.length<=0) return; const [beginTokenIndex, endTokenIndex] = Frame.getTokenSpan(frame); for (let iToken = beginTokenIndex; iToken < endTokenIndex; iToken++) { elevationTable[elevation][iToken] = true; } } function growElevationTableTo(elevationTable: boolean[][], elevation:number) { while (elevationTable.length <= elevation) { const newRow = elevationTable[0].map(()=>false); elevationTable.push(newRow); } } // get the number of elevations within a span function getElevationsWithinSpan(elevationTable:boolean[][], begin:number, end:number):number { let maxElevation = elevationTable.length - 1; for(let iElevation = maxElevation; iElevation>=0;iElevation--) { for(let iToken = begin; iToken