if not modules then modules = { } end modules ['anch-pos'] = { version = 1.001, comment = "companion to anch-pos.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } --[[ldx--

We save positional information in the main utility table. Not only can we store much more information in but it's also more efficient.

--ldx]]-- -- to be considered: store as numbers instead of string -- maybe replace texsp by our own converter (stay at the lua end) local tostring = tostring local concat, format, gmatch = table.concat, string.format, string.gmatch local lpegmatch = lpeg.match local allocate, mark = utilities.storage.allocate, utilities.storage.mark local texsp = tex.sp ----- texsp = string.todimen -- because we cache this is much faster but no rounding local collected = allocate() local tobesaved = allocate() local jobpositions = { collected = collected, tobesaved = tobesaved, } job.positions = jobpositions _ptbs_, _pcol_ = tobesaved, collected -- global local dx, dy, nx, ny = "0pt", "0pt", 0, 0 local function initializer() tobesaved = jobpositions.tobesaved collected = jobpositions.collected _ptbs_ = tobesaved -- global _pcol_ = collected -- global -- local p = collected["page:0"] -- page:1 -- if p then -- dx, nx = p[2] or "0pt", 0 -- dy, ny = p[3] or "0pt", 0 -- end end job.register('job.positions.collected', tobesaved, initializer) function jobpositions.copy(target,source) collected[target] = collected[source] or tobesaved[source] end function jobpositions.replace(name,...) collected[name] = {...} end function jobpositions.page(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[1]) else return 0 end end function jobpositions.x(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[2]) - nx else return 0 end end function jobpositions.y(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[3]) - ny else return 0 end end function jobpositions.width(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[4]) else return 0 end end function jobpositions.height(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[5]) else return 0 end end function jobpositions.depth(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[6]) else return 0 end end function jobpositions.xy(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[2]) - nx, texsp(jpi[3]) - ny else return 0, 0 end end function jobpositions.lowerleft(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[2]) - nx, texsp(jpi[3]) - texsp(jpi[6]) - ny else return 0, 0 end end function jobpositions.lowerright(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[2]) + texsp(jpi[4]) - nx, texsp(jpi[3]) - texsp(jpi[6]) - ny else return 0, 0 end end function jobpositions.upperright(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[2]) + texsp(jpi[4]) - nx, texsp(jpi[3]) + texsp(jpi[5]) - ny else return 0, 0 end end function jobpositions.upperleft(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[2]) - nx, texsp(jpi[3]) + texsp(jpi[5]) - ny else return 0, 0 end end function jobpositions.position(id) local jpi = collected[id] or tobesaved[id] if jpi then return texsp(jpi[1]), texsp(jpi[2]), texsp(jpi[3]), texsp(jpi[4]), texsp(jpi[5]), texsp(jpi[6]) else return 0, 0, 0, 0, 0, 0 end end function jobpositions.extra(id,n,default) -- assume numbers local jpi = collected[id] or tobesaved[id] if not jpi then return default else local split = jpi[0] if not split then split = lpegmatch(splitter,jpi[7]) jpi[0] = split end return texsp(split[n]) or default end end local function overlapping(one,two,overlappingmargin) one = collected[one] or tobesaved[one] two = collected[two] or tobesaved[two] if one and two and one[1] == two[1] then if not overlappingmargin then overlappingmargin = 2 end local x_one = one[2] local x_two = two[2] local w_two = two[4] local llx_one = x_one - overlappingmargin local urx_two = x_two + w_two + overlappingmargin if llx_one > urx_two then return false end local w_one = one[4] local urx_one = x_one + w_one + overlappingmargin local llx_two = x_two - overlappingmargin if urx_one < llx_two then return false end local y_one = one[3] local y_two = two[3] local d_one = one[6] local h_two = two[5] local lly_one = y_one - d_one - overlappingmargin local ury_two = y_two + h_two + overlappingmargin if lly_one > ury_two then return false end local h_one = one[5] local d_two = two[6] local ury_one = y_one + h_one + overlappingmargin local lly_two = y_two - d_two - overlappingmargin if ury_one < lly_two then return false end return true end end local function onsamepage(list,page) for id in gmatch(list,"(, )") do local jpi = collected[id] or tobesaved[id] if jpi then local p = jpi[1] if not page then page = p elseif page ~= p then return false end end end return page end jobpositions.overlapping = overlapping jobpositions.onsamepage = onsamepage -- interface commands.replacepospxywhd = jobpositions.replace commands.copyposition = jobpositions.copy function commands.MPp(id) local jpi = collected[id] or tobesaved[id] context(jpi and jpi[1] or '0') end function commands.MPx(id) local jpi = collected[id] or tobesaved[id] local x = jpi and jpi[2] if x then if nx == 0 then context(x) else context('\\the\\dimexpr%s-%s\\relax',x,dx) end else context('0pt') end end function commands.MPy(id) local jpi = collected[id] or tobesaved[id] local y = jpi and jpi[3] if y then if ny == 0 then context(y) else context('\\the\\dimexpr%s-%s\\relax',y,dy) end else context('0pt') end end function commands.MPw(id) local jpi = collected[id] or tobesaved[id] context(jpi and jpi[4] or '0pt') end function commands.MPh(id) local jpi = collected[id] or tobesaved[id] context(jpi and jpi[5] or '0pt') end function commands.MPd(id) local jpi = collected[id] or tobesaved[id] context(jpi and jpi[6] or '0pt') end function commands.MPxy(id) local jpi = collected[id] or tobesaved[id] if jpi then context('(%s-%s,%s-%s)',jpi[2],dx,jpi[3],dy) else context('(0,0)') end end function commands.MPll(id) local jpi = collected[id] or tobesaved[id] if jpi then context('(%s-%s,%s-%s-%s)',jpi[2],dx,jpi[3],jpi[6],dy) else context('(0,0)') end end function commands.MPlr(id) local jpi = collected[id] or tobesaved[id] if jpi then context('(%s+%s-%s,%s-%s-%s)',jpi[2],jpi[4],dx,jpi[3],jpi[6],dy) else context('(0,0)') end end function commands.MPur(id) local jpi = collected[id] or tobesaved[id] if jpi then context('(%s+%s-%s,%s+%s-%s)',jpi[2],jpi[4],dx,jpi[3],jpi[5],dy) else context('(0,0)') end end function commands.MPul(id) local jpi = collected[id] or tobesaved[id] if jpi then context('(%s-%s,%s+%s-%s)',jpi[2],dx,jpi[3],jpi[5],dy) else context('(0,0)') end end function commands.MPpos(id) local jpi = collected[id] or tobesaved[id] if jpi then context(concat(jpi,',',1,6)) else context('0,0,0,0,0,0') end end local splitter = lpeg.Ct(lpeg.splitat(",")) function commands.MPplus(id,n,default) local jpi = collected[id] or tobesaved[id] if not jpi then context(default) else local split = jpi[0] if not split then split = lpegmatch(splitter,jpi[7]) jpi[0] = split end context(split[n] or default) end end function commands.MPrest(id,default) local jpi = collected[id] or tobesaved[id] context(jpi and jpi[7] or default) end -- is testcase already defined? if so, then local function commands.doifpositionelse(name) commands.testcase(collected[name] or tobesaved[name]) end function commands.doifoverlappingelse(one,two,overlappingmargin) commands.testcase(overlapping(one,two,overlappingmargin)) end function commands.doifpositionsonsamepageelse(list,page) commands.testcase(onsamepage(list)) end function commands.doifpositionsonthispageelse(list) commands.testcase(onsamepage(list,tostring(tex.count.realpageno))) end