--neccesary to support the widget localisation and autoscaling local lcd=LCD or lcd local LCD_W = lcd.W or LCD_W local LCD_H = lcd.H or LCD_H --local RIGHT = RIGHT or 0 --fix 2.1 right alignement --local EVT_MINUS_FIRST = EVT_MINUS_FIRST or EVT_ROT_RIGHT or EVT_DOWN_BREAK --local EVT_PLUS_FIRST = EVT_PLUS_FIRST or EVT_ROT_LEFT or EVT_UP_BREAK --local EVT_ENTER_LONG = EVT_ENTER_LONG or EVT_ROT_LONG -- Copyright F. Aguerre & M. Ricci. -- This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License -- as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. -- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See theGNU General Public License for more details. -- Variable used to manage page and field edition *** do not change local edit = false -- true when editing field local saving = true local currPage = 1 -- current displayed page local currField = 0 -- current selected field local startValue = 0 -- value when start to press plus or minus key local workIndex, startIndex, workField, workAtt, workValue -- Working variables used in various function. -- Page title definition *** change to define your own title *** local pageTitle = {"PredimRC - AILE", "PredimRC - STAB", "PredimRC - FUSELAGE", "PredimRC - REGLAGE", "PredimRC - INFOS"} -- Page field definition *** change to define your own page content *** -- Field structure : {value, column, ligne, attribute, type, state, precision or combobox size, combobox list) -- > attribute can be DBLSIZE, MIDSIZE, SMLSIZE, XXLSIZE, and also LEFT, PREC1, PREC2 for number (if type = 1) -- > type can be 0 = text, 1 = number, 2 = combobox, ... can be extend if needed -- > state can be nil, false = read-only, true = read/write, 0 = selected, 1 = edited -- > precision (option) is the number of digit after the coma -- if 0 -> 100 is displayed 100 -- if PREC1 -> 100 is displayed 10.0 -- if PREC2 -> 100 is displayed 1.00 -- > combobox size (optional) is the size of the combobox -- > combobox list (optional) is the item list for the combobox -- Entête réutilisée dans les pages 1 (aile) et 2 (stab) local header = { -- Entete de colonne {"(mm)", 1, 12, 0, 0}, {"Trap.1", 40, 12, 0, 0}, {"Trap.2", 75, 12, 0, 0}, {"Trap.3", 110, 12, 0, 0}, {"Trap.4", 145, 12, 0, 0}, {"Trap.5", 180, 12, 0, 0}, -- Entete de ligne {"C. Max", 1, 22, 0, 0}, {"C. Min", 1, 32, 0, 0}, {"Long.", 1, 42, 0, 0}, {"Fleche", 1, 52, 0, 0}, } -- Définition des pages local pageField = { { -- Page 1/5 - Aile -- Entete de colonne header[1], header[2], header[3], header[4], header[5], header[6], -- Entete de ligne header[7], header[8], header[9], header[10], -- Trapeze 1 {250, 72, 22, 0, 1, true, 0}, -- corde maxi {150, 72, 32, 0, 1, true, 0}, -- corde mini {1000, 72, 42, 0, 1, true, 0}, -- longueur {100, 72, 52, 0, 1, true, 0}, -- fleche -- Trapeze 2 {0, 107, 22, 0, 1}, -- corde maxi {0, 107, 32, 0, 1, true, 0}, -- corde mini {0, 107, 42, 0, 1, true, 0}, -- longueur {0, 107, 52, 0, 1, true, 0}, -- fleche -- Trapeze 3 {0, 142, 22, 0, 1}, -- corde maxi {0, 142, 32, 0, 1, true, 0}, -- corde mini {0, 142, 42, 0, 1, true, 0}, -- longueur {0, 142, 52, 0, 1, true, 0}, -- fleche -- Trapeze 4 {0, 177, 22, 0, 1}, -- corde maxi {0, 177, 32, 0, 1, true, 0}, -- corde mini {0, 177, 42, 0, 1, true, 0}, -- longueur {0, 177, 52, 0, 1, true, 0}, -- fleche -- Trapeze 5 {0, 212, 22, 0, 1}, -- corde maxi {0, 212, 32, 0, 1, true, 0}, -- corde mini {0, 212, 42, 0, 1, true, 0}, -- longueur {0, 212, 52, 0, 1, true, 0} -- fleche }, { -- Page 2/5 - Stab -- Entete de colonne header[1], header[2], header[3], header[4], header[5], header[6], -- Entete de ligne header[7], header[8], header[9], header[10], -- Trapeze 1 {120, 72, 22, 0, 1, true, 0}, -- corde maxi {80, 72, 32, 0, 1, true, 0}, -- corde mini {270, 72, 42, 0, 1, true, 0}, -- longueur {40, 72, 52, 0, 1, true, 0}, -- fleche -- Trapeze 2 {0, 107, 22, 0, 1}, -- corde maxi {0, 107, 32, 0, 1, true, 0}, -- corde mini {0, 107, 42, 0, 1, true, 0}, -- longueur {0, 107, 52, 0, 1, true, 0}, -- fleche -- Trapeze 3 {0, 142, 22, 0, 1}, -- corde maxi {0, 142, 32, 0, 1, true, 0}, -- corde mini {0, 142, 42, 0, 1, true, 0}, -- longueur {0, 142, 52, 0, 1, true, 0}, -- fleche -- Trapeze 4 {0, 177, 22, 0, 1}, -- corde maxi {0, 177, 32, 0, 1, true, 0}, -- corde mini {0, 177, 42, 0, 1, true, 0}, -- longueur {0, 177, 52, 0, 1, true, 0}, -- fleche -- Trapeze 5 {0, 212, 22, 0, 1}, -- corde maxi {0, 212, 32, 0, 1, true, 0}, -- corde mini {0, 212, 42, 0, 1, true, 0}, -- longueur {0, 212, 52, 0, 1, true, 0} -- fleche }, { -- Page 3/5 - Fuselage {"STAB", 1, 10, 0 , 0}, {"Levier :", 40, 10, 0 , 0}, {700, 145, 10, 0, 1, true, 0}, {"Ouv. :", 150, 10, 0 , 0}, {0, 212, 10, 0, 2, true, 30, {180, 120, 115, 110, 105, 90}}, {"Haut :", 40, 20, 0 , 0}, {50, 145, 20, 0, 1, true, 0}, {"FUSO", 1, 30, 0, 0}, {"Poutre :", 40, 30, 0 , 0}, {1, 145, 30, 0, 2, true, 54, {"Fine", "Normale", "Epaisse", "Jet"}}, {"Longueur :", 40, 40, 0 , 0}, {1070, 145, 40, 0, 1, true, 0}, {"Nez :", 150, 40, 0 , 0}, {250, 212, 40, 0, 1, true, 0}, {"Largeur :", 40, 50, 0 , 0}, {50, 145, 50, 0, 1, true, 0} }, { -- Page 4/5 - Réglage {"Marge", 1, 12, 0 , 0}, {3, 78, 12, 0, 2, true, 25, {"6%", "5%", "4%", "3%", "2%", "1%"} }, {"CG", 1, 24, 0 , 0}, {0, 71, 24, 0, 1, false, PREC1}, {"%", 72, 24, 0, 0}, {0, 126, 24, 0, 1, false, PREC1}, {"mm", 127, 24, 0, 0}, {"Foyer", 1, 36, 0 , 0}, {0, 71, 36, 0, 1, false, PREC1}, {"%", 72, 36, 0, 0}, {0, 126, 36, 0, 1, false, PREC1}, {"mm", 127, 36, 0, 0} }, { -- Page 5/5 - Infos {"Surf.", 47, 10, 0, 0}, {"C.Moy.", 80, 10, 0,0}, {"Env.", 122, 10, 0, 0}, {"All.", 162, 10, 0, 0}, {"Foyer", 180, 10, 0, 0}, {"AILE", 1, 20, 0, 0}, {0, 73, 20, 0, 1, false, PREC2}, -- surface aero (dm2) {0, 108, 20, 0, 1, false, PREC1}, -- corde moyenne areo {0, 143, 20, 0, 1, false, 0}, -- envergure aero {0, 178, 20, 0, 1, false, PREC1}, -- allongement aero {0, 210, 20, 0, 1, false, PREC1}, -- foyer aero {"STAB", 1, 32, 0, 0}, {0, 73, 32, 0, 1, false, PREC2}, -- surface aero (dm2) {0, 108, 32, 0, 1, false, PREC1}, -- corde moyenne areo {0, 143, 32, 0, 1, false, 0}, -- envergure aero {0, 178, 32, 0, 1, false, PREC1}, -- allongement aero {0, 210, 32, 0, 1, false, PREC1}, -- foyer aero {"Levier", 40, 42, 0, 0}, -- Distance Foyer stab - Foyer Aile {0, 108, 42, 0, 1, false, 0}, {"Vol.", 126, 42, 0, 0}, -- Volume du stab {0, 178, 42, 0, 1, false, PREC2}, {"FUSO", 1, 54, 0, 0}, {"Surf.", 40, 54, 0, 0}, -- Surface projetée du fuselage {0, 108, 54, 0, 1, false, PREC1}, {"Foyer", 115, 54, 0, 0}, -- Foyer du fuselage {0, 172, 54, 0, 1, false, 0}, {"%", 173, 54, 0, 0}, } } -- Champs réutilisés dans les calculs local wingMean = pageField[5][8] local wingSpan = pageField[5][9] local wingRatio = pageField[5][10] local wingCenter = pageField[5][11] local stabMean = pageField[5][14] local stabSpan = pageField[5][15] local stabRatio = pageField[5][16] local stabCenter = pageField[5][17] local dist_FS_FA = pageField[5][19] local stabVol = pageField[5][21] -- Coefficient liés au combobox local coeffMarge = {0.06, 0.05, 0.04, 0.03, 0.02, 0.01} -- Marge pour le calcul du centrage local coeffCenterNormal = {0.15, 0.20, 0.25, 0.45} -- Coefficient pour le calcul du foyer du fuselage selon la poutre local coeffCenterCanard = {0.449, 0.35, 0.25, 0.45} -- Coefficient pour le calcul du foyer du fuselage selon la poutre pour un canard local coeffPoutre = {0.55, 0.7, 0.85, 1} -- Coefficient pour le calcul de la surface du fuselage selon la poutre -- Variable conservée pour les calculs local wingArea, stabArea, stabProjArea, bodyArea = 0, 0, 0, 0 local wingA, stabA, bodyA = 0, 0, 0 -- Process surface change local area, span, mean, ratio, center, surfaceA, FlCm, FlCm2, surface local wrkRoot, wrkSum, wrkArea, wrkMean, wrkOffset local function surfaceChange() area, span, mean, ratio, center, surfaceA = 0, 0, 0, 0, 0, 0 FlCm, FlCm2, wrkRoot = 0, 0, 0 surface = pageField[currPage] for index = 11, #surface, 4 do if surface[index][1] > 0 then surface[index][6] = true surface[index + 1][6] = true surface[index + 2][6] = true surface[index + 3][6] = true wrkSum = 3 * (surface[index][1] + surface[index + 1][1]) if wrkSum > 0 then -- calcul de l'envergure et de la surface span = span + surface[index + 2][1] wrkArea = surface[index + 2][1] * (surface[index][1] + surface[index + 1][1]) / 2 area = area + wrkArea -- calcul de la corde moyenne wrkMean = surface[index + 1][1] + (2 * surface[index][1] + surface[index + 1][1]) * (surface[index][1] - surface[index + 1][1]) / wrkSum mean = mean + wrkArea * wrkMean -- calcul de l'offset du foyer wrkOffset = wrkRoot + (surface[index + 3][1] - wrkRoot) * (surface[index][1] + 2 * surface[index + 1][1]) / wrkSum center = center + (wrkArea * (wrkOffset + 0.25 * wrkMean)) wrkRoot = surface[index + 3][1] end else surface[index][6] = false surface[index + 1][6] = false surface[index + 2][6] = false surface[index + 3][6] = false end end if area > 0 then mean = mean / area center = center / area area = 2 * area span = 2 * span ratio = span * span / area -- Calcul du facteur A pour la surface FlCm = center + 0.25 * mean - pageField[currPage][11][1] / 2 FlCm2 = math.atan(FlCm / (0.5 * span * 0.53)) surfaceA = ratio / (math.sqrt((ratio / math.cos(FlCm2))^2 + 4) + 2) end -- Conserve les calculs pour l'aile ou le stab if currPage == 1 then wingArea = area pageField[5][7][1] = area / 10000 -- surface aero (dm2) wingMean[1] = mean wingSpan[1] = span wingRatio[1] = ratio wingCenter[1] = center wingA = surfaceA else stabArea = area pageField[5][13][1] = area / 10000 -- surface aero (dm2) stabMean[1] = mean stabSpan[1] = span stabRatio[1] = ratio stabCenter[1] = center stabA = surfaceA ~= 0 and surfaceA or 0.000001 end end -- Process application changes local dist_FF_FA, coeffCenter, rx, rh2, racine, eMS, denom local foyerBrut, corrSillage, corrFuselage, pourcent local function commonChange() -- calcul liés au stab dist_FS_FA[1] = 0 stabVol[1] = 0 if wingArea > 0 and stabArea > 0 then -- calcul de la surface projetee du stab stabProjArea = stabArea * math.sin(math.rad(pageField[3][5][8][1 + pageField[3][5][1]]/2))^2 -- calcul de la distance de foyer aile à foyer stab dist_FS_FA[1] = pageField[3][3][1] - wingCenter[1] + stabCenter[1] -- calcul du volume du stab stabVol[1] = (stabProjArea * dist_FS_FA[1]) / (wingArea * wingMean[1]) end -- effectue le calcul du CG et du foyer seulement si la corde moyenne, l'envergure et l'allongement sont différent de zero if wingMean[1] ~= 0 and wingSpan[1] ~= 0 and wingRatio[1] ~= 0 then -- calculs liés au fuselage coeffCenter = 0 if stabVol[1] >= 0 then coeffCenter = coeffCenterNormal[1 + pageField[3][10][1]] else coeffCenter = coeffCenterCanard[1 + pageField[3][10][1]] end pageField[5][26][1] = 100 * coeffCenter dist_FF_FA = pageField[3][12][1] * coeffCenter - (pageField[3][14][1] + wingCenter[1]) bodyA = 0 if bodyArea > 0 then if stabVol[1] > 0.2 then bodyA = 0.2 * (1 + wingMean[1] / pageField[3][16][1]) * (stabVol[1] < 10 and wingA or 1) elseif stabVol[1] < -0.2 then bodyA = 0.2 * stabA * (1 + stabMean[1] / pageField[3][16][1]) else bodyA = 0.1 end end -- calcul de la déflexion du sillage (eMS) rx = 2 * dist_FS_FA[1] / wingSpan[1] rh2 = (2 * pageField[3][7][1] / wingSpan[1])^2 racine = math.sqrt(math.pi^2 / 16 + rx^2 + rh2) eMS = ((racine + rx) / (math.pi^2 / 16 + rh2) + rx / (rx^2 + rh2)) / (racine * (2 + math.sqrt(4 + wingRatio[1]^2))) -- calcul des corrections foyerBrut, corrSillage, corrFuselage = 0, 0, 0 denom = 0.11 * (wingA * wingArea + (1 - eMS) * stabA * stabProjArea + bodyA * bodyArea) if denom ~= 0 then foyerBrut = 0.25 + 0.11 * stabA * dist_FS_FA[1] * stabProjArea /(wingMean[1] * denom) corrSillage = eMS * dist_FS_FA[1] * 0.11 * stabA * stabProjArea / (wingMean[1] * denom) corrFuselage = 0 - (0.11 * dist_FF_FA / wingMean[1]) * bodyA * bodyArea / denom end -- calcul du foyer pourcent = foyerBrut - corrSillage - corrFuselage pageField[4][9][1] = 100 * pourcent pageField[4][11][1] = wingCenter[1] + (pourcent - 0.25) * wingMean[1] -- calcul du CG pourcent = pourcent - coeffMarge[1 + pageField[4][2][1]] pageField[4][4][1] = 100 * pourcent pageField[4][6][1] = wingCenter[1] + (pourcent - 0.25) * wingMean[1] else -- remet à zéro le CG et le foyer pageField[4][4][1] = 0 pageField[4][6][1] = 0 pageField[4][9][1] = 0 pageField[4][11][1] = 0 end end -- Process changes *** function called by the framework when value has change within a page. Include your own page logic local function onChange() if currPage == 1 or currPage == 2 then for index = 11, #pageField[currPage], 4 do -- contrôle des valeur négatives (corde et longueur) if pageField[currPage][index][1] < 0 then pageField[currPage][index][1] = 0 end if pageField[currPage][index + 1][1] < 0 then pageField[currPage][index + 1][1] = 0 end if pageField[currPage][index + 2][1] < 0 then pageField[currPage][index + 2][1] = 0 end -- reporte la corde mini sur le trapèze suivant if index > 14 then pageField[currPage][index][1] = pageField[currPage][index - 3][1] end end -- effectue les calculs lié à la surface surfaceChange() elseif currPage == 3 then -- contrôle des valeur négatives (longueur, nez et largeur) if pageField[3][12][1] < 0 then pageField[3][12][1] = 0 end if pageField[3][16][1] < 0 then pageField[3][16][1] = 0 end -- effectue les calculs liés au fuselage bodyArea = pageField[3][12][1] * pageField[3][16][1] * coeffPoutre[1 + pageField[3][10][1]] pageField[5][24][1] = bodyArea / 10000 end -- effectue les caluls liés à plusieurs pages commonChange() end -- Framwork *** DO NOT change the code here under -- Add value to current field local function addField(value) if currField > 0 and currField <= #pageField[currPage] then workField = pageField[currPage][currField] if workField[5] == 1 then -- Number workField[1] = workField[1] + value * (workField[7] == PREC1 and 0.1 or (workField[7] == PREC2 and 0.01 or 1)) elseif workField[5] == 2 then -- Combobox workField[1] = (workField[1] - (value > 0 and 1 or -1)) % #workField[8] end end end -- Change display attribute to current field local function changeField(value) if currField > 0 and currField <= #pageField[currPage] then pageField[currPage][currField][6] = value end end -- Select the next or previous editable field local function selectField(step) if #pageField[currPage] < 1 then return end -- empty page workIndex = 1 + (currField - 1) % #pageField[currPage] startIndex = workIndex while true do workIndex = 1 + (workIndex + step - 1) % #pageField[currPage] if workIndex == startIndex then break end if pageField[currPage][workIndex][6] then changeField(true) currField = workIndex changeField(0) break end end end -- save entries local function savePage() if io then local filename = "/MODELS/" .. model.getInfo().name .. ".predim" .. currPage loadfile("/APPS/L/L/TABLE/save.lua")(pageField[currPage],filename) end end -- save entries local function loadPage() if io then local filename = "/MODELS/" .. model.getInfo().name .. ".predim" .. currPage local f=io.open(filename,"r") if f then io.close(f) f=nil pageField[currPage]=loadfile("/APPS/L/L/TABLE/load.lua")(filename)() end end saving = false end -- Select next or previous page local function selectPage(step) savePage() saving = true if currField > 0 then changeField(true) end currPage = 1 + (currPage + step -1) % #pageField currField = 0 selectField(1) end -- Redraw the current page local function redrawPage() lcd.clear() lcd.drawScreenTitle(pageTitle[currPage], currPage, #pageField) -- lcd.drawText(1,1,pageTitle[currPage]) -- lcd.drawText(LCD_W,1, "page " .. currPage .. "/" .. #pageField, RIGHT) for index = 1, #pageField[currPage], 1 do workField = pageField[currPage][index] workAtt = workField[6] == 0 and INVERS or (workField[6] == 1 and INVERS + BLINK or 0) -- determine the display attribut -- display text field if workField[5] == 0 then lcd.drawText(workField[2], workField[3], workField[1], workField[4] + workAtt) -- display number field elseif workField[5] == 1 then workAtt = workAtt + (workField[7] and workField[7] or 0) -- change the display attribut based on precision workValue = workField[7] == PREC1 and 10 or (workField[7] == PREC2 and 100 or 1) -- get the multiplication factor based on precision workValue = math.floor(workField[1] * workValue + 0.5) -- round the value based on the precision lcd.drawNumber(workField[2], workField[3], workValue, workField[4] + workAtt + RIGHT) -- display combobox except the selected / edited one elseif workField[5] == 2 and index ~= currField then -- Combobox lcd.drawCombobox(workField[2] - workField[7], workField[3] - 2, workField[7], workField[8], workField[1], workField[4] + workAtt) end end -- finaly if the current field is a combobox, display it if currField > 0 and pageField[currPage][currField][5] == 2 then workField = pageField[currPage][currField] workAtt = workField[6] == 0 and INVERS or (workField[6] == 1 and INVERS + BLINK or 0) lcd.drawCombobox(workField[2] - workField[7], workField[3] - 2, workField[7], workField[8], workField[1], workField[4] + workAtt) end end -- Init local function init() for index = 1, #pageField, 1 do currPage = index onChange() end currPage, currField, edit = 1, 0, false selectField(1) end -- Main local function run(event) if saving then loadPage() return 0 end if event == nil then error("Cannot be run as a model script!") return 2 elseif event == EVT_ENTER_BREAK then -- toggle editing/selecting current field edit = not edit changeField(edit and 1 or 0) redrawPage() elseif event == EVT_EXIT_BREAK then -- exit script selectPage(1) -- return 2 elseif edit then if event == EVT_PLUS_FIRST or event == EVT_MINUS_FIRST then -- first in/decrease current field startValue = pageField[currPage][currField][1] addField(event == EVT_PLUS_FIRST and 1 or -1) onChange() elseif event == EVT_PLUS_REPT or event == EVT_MINUS_REPT then -- repeat in/decrease current field if math.abs(pageField[currPage][currField][1] - startValue) > 200 then addField(event == EVT_PLUS_REPT and 10 or -10) elseif math.abs(pageField[currPage][currField][1] - startValue) > 20 then addField(event == EVT_PLUS_REPT and 5 or -5) else addField(event == EVT_PLUS_REPT and 1 or -1) end onChange() -- process page changes end redrawPage() else if event == EVT_MINUS_FIRST then -- move to next editable field -- if event == EVT_MINUS_BREAK then -- move to next editable field selectField(1) -- elseif event == EVT_PLUS_BREAK then -- move to previous editable field elseif event == EVT_PLUS_FIRST then -- move to previous editable field selectField(-1) elseif event == EVT_PAGE_BREAK then -- move to next page selectPage(1) elseif event == EVT_ENTER_LONG then -- move to next page selectPage(1) elseif event == EVT_PAGE_LONG then -- move to previous page killEvents(event); selectPage(-1) end redrawPage() end return 0 end return { init=init, run=run}