--[[ @Title: Ancestors and Descendants - Counts by Generation @Author: Jane Taubman @Version: 1.3 @LastUpdated: 15 Dec 2020 @Description: Report of the number of Grandparents recorded for an individual by Generation and the number of direct decendants by Generation 1.1 Lua 5.3 Compatibility 1.2 V7 compatibility 1.3 Compute percentage and round before adding for V7 ]] function main() tblIndi = fhPromptUserForRecordSel('INDI',1) if #tblIndi == 0 then return end local pRoot = tblIndi[1] local iAncMax,iDecMax = 0,0 local tblAncGen = {} local tblDecGen = {} local TblAncestorDescriptions = {'Parents','Grandparents','Great Grandparents'} local TblDescendantDescriptions = {'Child','Grandchildren','Great Grandchildren'} for pi in records('INDI') do local bAnc = fhCallBuiltInFunction('IsAncestorOf',pi,pRoot) if bAnc then -- Ancestor of selected person get number of Generations local iGens = fhCallBuiltInFunction('RelationCode',pi,pRoot,'GENS_DOWN',1) if tblAncGen[iGens] then tblAncGen[iGens] = tblAncGen[iGens] + 1 else tblAncGen[iGens] = 1 end if iGens > iAncMax then iAncMax = iGens end end local bDec = fhCallBuiltInFunction('IsDescendantOf',pi,pRoot) if bDec then -- descendant of selected person get number of Generations local iGens = fhCallBuiltInFunction('RelationCode',pi,pRoot,'GENS_UP',1) print (fhGetDisplayText(pi),iGens) if tblDecGen[iGens] then tblDecGen[iGens] = tblDecGen[iGens] + 1 else tblDecGen[iGens] = 1 end if iGens > iDecMax then iDecMax = iGens end end end ------------------------------------- Output Results local tblResults = createResultTable() -- Define Columns tblResults.gen = {title='Gen',type=integer,align='align_left',width=80,sort=1} tblResults.desc = {title='Description',type='Text',width=140} tblResults.poss1 = {title='Pos',type='integer',align='align_right',width=40} tblResults.posssum = {title='Pos Sum',type='integer',align='align_right',width=40} tblResults.actual = {title='Actual',type='integer',align='align_right',width=40} tblResults.actualsum = {title='Actual Sum',type='integer',align='align_right',width=40} tblResults.percent = {title='%',type='integer',align='align_right',width=40} tblResults:newRow() tblResults.gen:set(1) local sum,psum = 1,1 tblResults.desc:set(fhGetDisplayText(pRoot)) tblResults.poss1:set(1) tblResults.posssum:set(sum) tblResults.actual:set(1) tblResults.actualsum:set(1) tblResults.percent:set(100) for i = 1, iAncMax do tblResults:newRow() local sTitle = '' if i<4 then sTitle = TblAncestorDescriptions[i] else sTitle = (i - 2)..'x '..TblAncestorDescriptions[3] end tblAncGen[i] = tblAncGen[i] or 0 tblResults.gen:set(i+1) tblResults.desc:set(sTitle) tblResults.poss1:set(2 ^i) psum = psum + 2^i sum = sum + tblAncGen[i] tblResults.posssum:set(psum) tblResults.actual:set(tblAncGen[i]) tblResults.actualsum:set(sum) local percent = math.floor((tblAncGen[i]/(2^i) * 100) + 0.5) tblResults.percent:set(percent) print (i,2 ^i,sTitle,tblAncGen[i] or 0) end sum = 0 for i = 1, iDecMax do tblResults:newRow() local sTitle = '' if i<4 then sTitle = TblDescendantDescriptions[i] else sTitle = (i - 2)..'x '..TblDescendantDescriptions[3] end tblDecGen[i] = tblDecGen[i] or 0 tblResults.gen:set((i+1) * -1) tblResults.desc:set(sTitle) tblResults.poss1:set(0) sum = sum + tblDecGen[i] tblResults.posssum:set(0) tblResults.actual:set(tblDecGen[i]) tblResults.actualsum:set(sum) tblResults.percent:set(0) -- print (i,2 ^i,sTitle,tblDecGen[i] or 0) end local sTitle = "Ancestor and Descendant Breakdown for "..fhGetDisplayText(pRoot) fhOutputResultSetTitles(sTitle, sTitle, "Created Date: %#x") tblResults:outputResults() end function records(type) local pi = fhNewItemPtr() local p2 = fhNewItemPtr() pi:MoveToFirstRecord(type) return function () p2:MoveTo(pi) pi:MoveNext() if p2:IsNotNull() then return p2 end end end function createResultTable() local tblOutput_mt = {} -- create metatable local iC = 0 -- Define count of lines local tblOutput = {} -- Define Columns Table tblOutput_mt.col = 0 tblOutput_mt.seq = {} tblOutput_mt.__newindex = function (t,k,v) -- Set Values to Defaults if not supplied if v.content == nil then v.content = {} end if v.title == nil then v.title = k end if v.type == nil then v.type = 'notset' end if v.width == nil then v.width = 140 end if v.align == nil then v.align = 'align_left' end if v.sort == nil then v.sort = 0 end if v.sortAscending == nil then v.sortAscending = true end if v.sortType == nil then v.sortType = 'default' end if v.visibility == nil then v. visibility = 'show' end v.set = function(self,value) self.content[iC] = value if self.type == 'notset' then if type(value) == 'string' then self.type = 'text' elseif type(value) == 'number' then self.type = 'integer' self.width = '30' else self.type = 'item' end end end rawset(t,k,v) -- update original table local m = getmetatable(t) m.col = m.col + 1 table.insert(m.seq,k) end tblOutput_mt.__call = function (t) local i = 0 local m = getmetatable(t) local n = table.getn(m.seq) return function () i = i + 1 if i <= n then return t[m.seq[i]] end end end tblOutput.newRow = function(t) iC = iC + 1 end tblOutput.rowCount = function(t) return iC end tblOutput.outputResults = function(self) for l in self() do fhOutputResultSetColumn(l.title, l.type, l.content, iC, l.width,l.align,l.sort,l.sortAscending,l.sortType,l.visibility ) end end setmetatable(tblOutput, tblOutput_mt) return tblOutput end ---------------------------------------------------------------- Lua 5.3 if not(table.getn) then if fhGetAppVersion() > 6 then function table.getn(t) local count = 0 for _, __ in pairs(t) do count = count + 1 end return count end function unpack(t) return table.unpack(t) end end end ---------------------------------------------------------------- Run Main main()