require 'math' --[[ keypoints: sorted array of {x, y} pairs ('x' values should increase strongly monotonic!), e.g. { {0, 0.9}, {0.4, 0}, {0.6, 0.2}, {0.8, 1.0} } pos: a position on the 'x' axis, e.g. 0.5 return: the value corresponding to 'pos' that was linear interpolated from the 'keypoints' line chain (e.g. 0.1 for the example input data) --]] function roadbookMapInterpolated(keypoints, pos) local idx = 1 while ((idx + 1 < #keypoints) and (pos > keypoints[idx + 1][1])) do idx = idx + 1 end local secondidx = math.min(#keypoints, idx + 1) local k0 = keypoints[idx][1] local v0 = keypoints[idx][2] local k1 = keypoints[secondidx][1] local v1 = keypoints[secondidx][2] local lpos = 0.0 if (k1 > k0) then lpos = math.min(1.0, math.max(0.0, (pos - k0) / (k1 - k0))) end local result = v0 * (1.0 - lpos) + v1 * lpos print(pos, " ", idx, " ", secondidx, " ", k0, " ", v0, " ", k1, " ", v1, " ", lpos, " ", result) return result end --[[ state: the guidance state return: opacity: the opacity of the deviate content --]] function roadbookDeviateContentOpacity(state) if state == ROADBOOK_GUIDANCE_STATE_DEVIATE then return 1.0 else return 0.0 end end function roadbookAsiaCcpOpacity(state) if state == ROADBOOK_GUIDANCE_STATE_CALCULATION_ASIA or state == ROADBOOK_GUIDANCE_STATE_INACTIVE_ASIA or state == ROADBOOK_GUIDANCE_STATE_OFFROAD_ASIA then return 1.0 else return 0.0 end end --[[ state: the guidance state enabled: roadbook is selected mapVisible: whether a map screen (which can contain the flying window) is visible return: visibility: the visibility of the destination information (as a bool) opacity: the visibility of the destination information (as either 1.0 or 0.0) --]] function roadbookDestinationVisibility(state, enabled, mapVisible) local ret = (not mapVisible) and enabled and (state == ROADBOOK_GUIDANCE_STATE_ACTIVE or state == ROADBOOK_GUIDANCE_STATE_OFFROAD or state == ROADBOOK_GUIDANCE_STATE_DEVIATE or state == ROADBOOK_GUIDANCE_STATE_OFFROAD_ASIA) if ret then return true, 1.0 else return false, 0.0 end end --[[ state: the guidance state isEce: should contain true for ECE or US enabled: roadbook is selected bendDelay: a delay time for the bend (usually negative) currentBend: current bend of bend animation bendThreshold: bending threashold if the content will be visible return: bend: the bend value for the road contentVisible: the visibility of the roadbook panels detailedContentVisible: the visibility of the detailed content laneguidingVisible: the visibility of the three LG rows and the separator compassVisible: the visibility of the (non asia) compass --]] function roadbookGuidanceStateRelated(state, isEce, enabled, bendDelay, currentBend, bendThreshold) local panelsVisible = (state == ROADBOOK_GUIDANCE_STATE_ACTIVE or state == ROADBOOK_GUIDANCE_STATE_DEVIATE) local roadBend = bendDelay if panelsVisible then roadBend = 1.0 end local detailedContentVisible = (panelsVisible or state == ROADBOOK_GUIDANCE_STATE_INACTIVE_ASIA) -- TODO: will this lead to instantly vanishing lane guiding on state change?? local lgVisible = (state == ROADBOOK_GUIDANCE_STATE_ACTIVE) local compassVisible = isEce local contentVisible = enabled and panelsVisible and (currentBend > bendThreshold) return roadBend, contentVisible, enabled and detailedContentVisible, enabled and lgVisible, enabled and compassVisible end --[[ opacity: opacity to be used when visible visible: if false, the resulting opacity will be 0 return: effectiveOpacity: Either input opacity or 0, depending on "visible" --]] function roadbookEffectiveOpacity(opacity, visible) if visible then return opacity else return 0 end end --[[ progress: the progress of the bargraph assetSize: size of the bargraph asset return: position: vertical bottom position of the bar graph component size: vertical size of the bar graph component --]] function roadbookBargraphPlacement(progress, assetSize) -- always at least 9 px high, as the bottom + top images have that size local size = 9 + ( (assetSize.z - 2*6 - 9) * (100.0 - progress) / 100.0 ) return assetSize.z - 6.0 - size , size end --[[ currentOpacity: The current opacity for the whole widget contentOpacity: The animated opacity for the content loadingOpacity: The animated opacity for the loading indicator return: contentOpacity: Calculated opacity for the content loadingOpacity: Calculated opacity for the loading indicator --]] function calculatePanelContentOpacity(currentOpacity, contentOpacity, loadingOpacity) return currentOpacity * contentOpacity, currentOpacity * loadingOpacity end --[[ trafficIconsVisibility: [0, 1] for the visibility of traffic icons and divider bar (causes other elements to be shifted) opacity: the current opacity of the widget maxTextLineWidth: the maximum width of the text widget xStartWithOutTrafficIcons: x-offset without traffic icons displayed xStartWithTrafficIcons: x-offset with traffic icons displayed return: textLineSize: layout related size vector of the icon text line and the service icons doubleTextLineSize: layout related size vector of the two-lined text widget iconTextPosition: layout related position vector of the icon text line and the two-lined text widget serviceIconPosition: layout related position vector of the service icons directionPosition: layout related position vector of the direction arrow trafficElementsOpacity: opacity of traffic related content --]] function roadbookFrontContentLayout(trafficIconsVisibility, opacity, maxTextLineWidth, xStartWithOutTrafficIcons, xStartWithTrafficIcons) -- TODO: shift direction position less? (only 35px?) local xOffset = roadbookMapInterpolated({{0.0, xStartWithOutTrafficIcons}, {0.6, xStartWithTrafficIcons}}, trafficIconsVisibility); local trafficOpa = roadbookMapInterpolated({{0.7, 0.0}, {1.0, 1.0}}, trafficIconsVisibility); local textLineSize = {x=maxTextLineWidth - xOffset, y=0, z=40} local doubleTextLineSize = {x=maxTextLineWidth - xOffset, y=0, z=90} local iconTextPosition = {x=25 + xOffset, y=0, z=-52} local serviceIconPosition = {x=25 + xOffset, y=0, z=-97} local directionPosition = {x=35 + xOffset, y=0, z=-212} local trafficElementsOpacity = opacity * trafficOpa return textLineSize, doubleTextLineSize, iconTextPosition, serviceIconPosition, directionPosition, trafficElementsOpacity end --[[ return: tunnelIconOpacity: the current opacity for the widgets in tunnel maneuver layout barGraphPosition: the bar graph widget position (not in tunnels, only normal and Asia Branch) distancePosition: the distance text position for the widgets in non-tunnel maneuver layout --]] function roadboookBlowupContentLayout(isTunnelLayout, opacity, distanceVerticalOffset, distanceHorizontalOffset, barGraphVerticalOffset, barGraphHorizontalOffset) local tunnelIconOpacity = 0.0 local px = 332 local py = -438 local of = 1.9 -- shadow/outline x/y offset if isTunnelLayout then tunnelIconOpacity = opacity px = 234 end py = py + distanceVerticalOffset local barGraphPosition = {x=px + 170 + barGraphHorizontalOffset, y=0, z=py + 63 + barGraphVerticalOffset} return tunnelIconOpacity, barGraphPosition, {x=px + distanceHorizontalOffset, y=0, z=py} end --[[ size: the given size vector return: a size vector where z is divided by 2 --]] function roadbookTrafficSegmentSize(size) return {x = size.x, y = size.y, z = size.z/2} end function roadbookDelayOpacity(delayTimeString, baseOpacity) if delayTimeString == "" then return 0.0 end return baseOpacity end --[[ guidanceState: the guidance state headlineContentVisible: is there any DTD/ETA/... info visible? return: opacity of the black headline background sortOrder of the black headline background --]] function roadbookHeadlineBackground(guidanceState, headlineContentVisible) if headlineContentVisible and (guidanceState == ROADBOOK_GUIDANCE_STATE_OFFROAD or guidanceState == ROADBOOK_GUIDANCE_STATE_OFFROAD_ASIA) then return 1.0, 0 elseif guidanceState == ROADBOOK_GUIDANCE_STATE_CALCULATION or guidanceState == ROADBOOK_GUIDANCE_STATE_CALCULATION_ASIA then return 1.0, 6 else return 0.0, 0 end end --[[ guidanceState: the guidance state return: opacity of the "Calculating route..." text --]] function roadbookHeadlineCalculatingText(guidanceState) if guidanceState == ROADBOOK_GUIDANCE_STATE_CALCULATION or guidanceState == ROADBOOK_GUIDANCE_STATE_CALCULATION_ASIA then return 1.0 else return 0.0 end end function roadbookLabelsGuidanceState(guidingStep, isDoubleManeuver, parentOpacity) opacityDirection = parentOpacity opacityDtM = parentOpacity opacityComingRoad = parentOpacity opacityGS3 = parentOpacity layerEnabled = false opacityFrame = parentOpacity opacityFrameDoubleManeuver = 0.0 if guidingStep == ROADBOOK_GS_3_1 or guidingStep == ROADBOOK_GS_3_2 then opacityComingRoad = 0.0 opacityDtM = 0.0 opacityComingRoad = 0.0 opacityDirection = 0.0 opacityFrameDoubleManeuver = 0.0 layerEnabled = true else opacityGS3 = 0.0 if isDoubleManeuver == true then opacityDirection = parentOpacity * 0.5 opacityDtM = 0.0 opacityComingRoad = 0.0 opacityFrameDoubleManeuver = parentOpacity opacityFrame = 0.0 elseif guidingStep == ROADBOOK_GS_1 or guidingStep == ROADBOOK_GS_0 then opacityComingRoad = 0.0 end end return opacityDirection, opacityDtM, opacityComingRoad, opacityFrame, opacityFrameDoubleManeuver, opacityGS3, layerEnabled end function roadbookLabelsGuidanceLaneGuidingState(guidingStep, parentOpacity, useCutoutFrame) opacity = parentOpacity opacityCutoutFrame = parentOpacity if guidingStep == ROADBOOK_GS_1 then opacityCutoutFrame = 0.0 end if useCutoutFrame == true then opacityNormalFrame = parentOpacity - opacityCutoutFrame else opacityNormalFrame = parentOpacity end return opacity, opacityNormalFrame, opacityCutoutFrame end function roadbookLabelsGuidanceStateSize(guidingStep, width, showComingRoad) height = 103.0 if guidingStep == ROADBOOK_GS_1 or guidingStep == ROADBOOK_GS_0 then height = 60.0 elseif guidingStep == ROADBOOK_GS_3_1 or guidingStep == ROADBOOK_GS_3_2 then height = 232.0 if showComingRoad then height = height + 45.0 end end return { x=width, y=0.0, z=height } end function roadbookCurrentLaneIndicatorPosition(laneIndicatorPosition, basePosition) xValue = laneIndicatorPosition return { x=basePosition.x + xValue, y=basePosition.y, z=basePosition.z } end function roadbookLabelsGuidanceLanePosition(laneCount, offset) width = 4.0 + 8.0 - 1.0 + laneCount * ( 36.0 + 4.0 ) width = width + offset; height = 0.0 return { x=width, y=0.0, z=height } end function roadbookLabelsGuidanceBackgroundOpacity(parentOpacity, guidingStep) opacityGS1 = parentOpacity opacityGS2 = parentOpacity if guidingStep == ROADBOOK_GS_1 then opacityGS2 = 0 else opacityGS1 = 0 end return opacityGS1, opacityGS2 end --[[ numberOfLanes: number of available lanes currentLaneIndex: the index of the current lane return: visibility of the current lane position of the current lane position of the current lane separator position of the current lane sector --]] function roadbookLabelLaneProperties(numberOfLanes, currentLaneIndex, positionOffset) pos = -40.0 * ( numberOfLanes - currentLaneIndex ) separatorPos = pos - 4.0 positionOffset.x = positionOffset.x + pos visibility = 0.0 if numberOfLanes >= currentLaneIndex and numberOfLanes ~= 0 then visibility = 1.0 end return visibility, positionOffset, { x=separatorPos, y=0.0, z=0.0 }, { x=pos, y=0.0, z=8.0 } end function roadbookLabelsComingRoadFadeDelay( opacityTo ) if opacityTo > 0 then return 500 end return 1 end function roadbookLabelsBarGraphFadeDelay( opacityTo ) delay = 1 if opacityTo > 0 then delay = 500 end return delay end function roadbookLabelsHighguidingFadeDuration( opacityTo, animDuration ) duration = 1 if opacityTo > 0 then duration = animDuration end return duration end function roadbookLabelsHighguidingSize( size, showComingRoad ) size.x = size.x - 12.0 size.z = size.z - 11.0 if showComingRoad then size.z = size.z - 45.0 end if size.x < 0.0 then size.x = 0.0 end if size.z < 0.0 then size.z = 0.0 end return size end function roadbookLabelsComingRoadLineSizeScript( width ) spacerWidth = 10.0 sizeX = width - spacerWidth - spacerWidth -- start and end spacers return { x=sizeX, y=0.0, z=41.0 } end function roadbookLabelsDistanceLineSizeScript( width ) spacerWidth = 10.0 iconWidth = 113.0 iconRightBorderTransparency = 45.0 sizeX = width - iconWidth + iconRightBorderTransparency - spacerWidth - spacerWidth - spacerWidth -- spacers at start and end and between icon/distance return { x=sizeX, y=0.0, z=41.0 } end function roadbookLabelLaneGS2BackgroundOpacity( opacity, useCutoutFrame ) if useCutoutFrame == true then return opacity end return 0.0 end function roadbookLabelsLaneGuidingBackgroundSize( guidingStep, gs1Size, gs2Size, useCutoutFrame ) if guidingStep == 1 then return gs1Size end if useCutoutFrame == true then return gs1Size end return gs2Size end function roadbookLabelsComingRoadBackgroundSize( size ) if size.z > 42.0 then size.z = 42.0 end size.x = size.x - 12.0 if size.x < 0.0 then size.x = 0.0 end return size end function roadbookLabelsComingRoadLineSize( size ) if size.z > 47.0 then size.z = 47.0 end size.x = size.x - 20.0 if size.x < 0.0 then size.x = 0.0 end return size end function roadbookLabelsComingRoadPosition( size ) size.x = 0.0 size.z = size.z - 47.0 return size end function roadbookTextOutlinePositions( size ) return { x=-size, y=0.0, z=-size }, { x=-size, y=0.0, z=size }, { x=size, y=0.0, z=-size }, { x=size, y=0.0, z=size } end --[[ widgetTopOffset: the amount of pixels that the layer widget (height = 485) is shifted downwards, with 0 it being aligned with the top of the screen widgetWidth: the size of the texture image widget widgetHeight: see above widgetExtraOffset: a vec3 that is subtracted from the widgetWidth/Height (i.e. can be used to expand/shrink the widget size) return: a (x,y, w,h) texture coordinate vector --]] function roadbookAssetLayerMaskTexCoords(widgetTopOffset, widgetWidth, widgetHeight, widgetExtraOffset) local texWidth = 32 local texHeight = 96 local texCoordW = (widgetWidth - widgetExtraOffset.x) / texWidth local texCoordH = (widgetHeight - widgetExtraOffset.z) / texHeight local texCoordStartOffsetY = (55.0 - widgetTopOffset) / texHeight return { x=0.0, y=texCoordStartOffsetY, z=texCoordW, w=texCoordH } end --[[ carHeading: heading of the car [0..1[ return: rotation value [0..360[ --]] function roadbookFlatCompassScalesRotation(carHeading) return { x=0.0, y=carHeading*360.0, z=0.0 } end --[[ offset: current offset [0..1] range: +- threashold return: mapped value from [0-range..1+range] --]] function roadbookMapAlphaMaskValue( offset, range ) return ( 1.0 + range * 2.0 ) * offset - range end --[[ panelPos: current panel position [0.0..5.0] (S_FUTURE, S_FAR, S_NEAR, S_FRONT, S_BLOWUP, S_BEHIND) blowUp: current blowup value return: previewContentOpacity previewTrafficContentOpacity fullContentOpacity --]] function roadbookMapPanelPositionToOpacity( panelPos, blowUp, isDeviate ) local S_FUTURE = 0.0 local S_FAR = 1.0 local S_NEAR = 2.0 local S_NEAR_FRONT = 2.5 local S_FRONT = 3.0 local S_FRONT_BLOWUP = 3.5 local S_BLOWUP = 4.0 local S_BEHIND = 5.0 if isDeviate == true then return 0.0, 0.0, 0.0 end panelPos = panelPos + 1 local previewContentOpacity = roadbookMapInterpolated({{S_FUTURE, 0.0}, {S_FAR, 0.29}, {S_NEAR, 0.55}, {S_NEAR_FRONT, 0.0}}, panelPos) local previewTrafficContentOpacity = roadbookMapInterpolated({{S_FUTURE, 0.0}, {S_FAR, 0.6}, {S_NEAR, 0.8}, {S_NEAR_FRONT, 0.0}}, panelPos) local fullContentOpacity = roadbookMapInterpolated({{S_NEAR_FRONT, 0.0}, {S_FRONT, 1.0}, {S_FRONT_BLOWUP, 0.0}, {S_BEHIND, 0.0}}, panelPos) local blowUpScale = roadbookMapInterpolated({{1.0, 1.0}, {2.0, 0.0}}, blowUp) fullContentOpacity = fullContentOpacity * blowUpScale return previewContentOpacity, previewTrafficContentOpacity, fullContentOpacity end