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