1if not modules then modules = { } end modules ['grph-rul'] = {
2 version = 1.001,
3 comment = "companion to grph-rul.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local tonumber, next, type = tonumber, next, type
10local concat = table.concat
11
12local attributes = attributes
13local nodes = nodes
14local context = context
15
16local bpfactor = number.dimenfactors.bp
17
18local nuts = nodes.nuts
19local nodepool = nuts.pool
20local userrule = nuts.rules.userrule
21local outlinerule = nuts.pool.outlinerule
22local ruleactions = nuts.rules.ruleactions
23
24local setattrlist = nuts.setattrlist
25local setattr = nuts.setattr
26local tonode = nuts.tonode
27
28local getattribute = tex.getattribute
29local getwhd = nuts.getwhd
30local setwhd = nuts.setwhd
31
32local lefttoright_code = nodes.dirvalues.lefttoright
33
34local a_color = attributes.private('color')
35local a_transparency = attributes.private('transparency')
36local a_colormodel = attributes.private('colormodel')
37
38local mpcolor = attributes.colors.mpcolor
39
40local trace_mp = false trackers.register("rules.mp", function(v) trace_mp = v end)
41
42local report_mp = logs.reporter("rules","mp")
43
44local floor = math.floor
45local getrandom = utilities.randomizer.get
46local formatters = string.formatters
47
48
49
50local pdfprint
51
52pdfprint = function(...) pdfprint = lpdf.print return pdfprint(...) end
53
54updaters.register("backend.update",function()
55 pdfprint = lpdf.print
56end)
57
58do
59
60 local simplemetapost = metapost.simple
61 local cachesize = 0
62 local maxcachesize = 256*1024
63 local cachethreshold = 1024
64 local caching = false
65
66
67
68
69 local cache = table.setmetatableindex(function(t,k)
70 local v = simplemetapost("rulefun",k)
71 cachesize = cachesize + #v
72 if cachesize > maxcachesize then
73
74 for k, v in next, t do
75 local n = #v
76 if n > cachethreshold then
77 t[k] = nil
78 cachesize = cachesize - n
79 end
80 end
81
82 end
83
84 t[k] = v
85 return v
86 end)
87
88 local replacer = utilities.templates.replacer
89
90
91
92 local predefined = {
93 ["fake:word"] = replacer [[
94FakeWord(%width%,%height%,%depth%,%line%,%color%);
95 ]],
96 ["fake:rule"] = replacer[[
97%initializations%
98FakeRule(%width%,%height%,%depth%,%line%,%color%);
99 ]],
100 ["fake:rest"] = replacer [[
101RuleDirection := "%direction%" ;
102RuleOption := "%option%" ;
103RuleWidth := %width% ;
104RuleHeight := %height% ;
105RuleDepth := %depth% ;
106RuleH := %h% ;
107RuleV := %v% ;
108RuleThickness := %line% ;
109RuleFactor := %factor% ;
110RuleOffset := %offset% ;
111def RuleColor = %color% enddef ;
112%data%;
113 ]]
114 }
115
116 local initialized = false ;
117
118 ruleactions.mp = function(p,h,v,i,n)
119 local name = p.name or "fake:rest"
120 local code = (predefined[name] or predefined["fake:rest"]) {
121 data = p.data or "",
122 width = p.width * bpfactor,
123 height = p.height * bpfactor,
124 depth = p.depth * bpfactor,
125 factor = (p.factor or 0) * bpfactor,
126 offset = p.offset or 0,
127 line = (p.line or 65536) * bpfactor,
128 color = mpcolor(p.ma,p.ca,p.ta),
129 option = p.option or "",
130 direction = p.direction or lefttoright_code,
131 h = h * bpfactor,
132 v = v * bpfactor,
133 }
134 if not initialized then
135 initialized = true
136 simplemetapost("rulefun",formatters["randomseed := %s;"](getrandom("rulefun",0,4095)))
137 end
138
139
140 local pdf = caching and cache[code] or simplemetapost("rulefun",code,true)
141 if trace_mp then
142 report_mp("code: %s",code)
143 report_mp("pdf : %s",pdf)
144 end
145 if pdf and pdf ~= "" then
146 pdfprint("direct",pdf)
147 end
148 end
149
150end
151
152do
153
154
155
156
157
158 local function round(p,kind)
159 local method = tonumber(p.corner) or 0
160 if method < 0 or method > 27 then
161 method = 0
162 end
163 local width = p.width or 0
164 local height = p.height or 0
165 local depth = p.depth or 0
166 local total = height + depth
167 local radius = p.radius or 655360
168 local line = p.line or 65536
169 local how = (method > 8 or kind ~= "fill") and "S" or "f"
170 local half = line / 2
171 local xmin = half * bpfactor
172 local xmax = ( width - half) * bpfactor
173 local ymax = ( height - half) * bpfactor
174 local ymin = (-depth + half) * bpfactor
175 local full = ( radius + half)
176 local xxmin = full * bpfactor
177 local xxmax = ( width - full) * bpfactor
178 local yymax = ( height - full) * bpfactor
179 local yymin = (-depth + full) * bpfactor
180 line = line * bpfactor
181 if xxmin <= xxmax and yymin <= yymax then
182 local list = nil
183 if method == 0 then
184 list = {
185 "q", line, "w", xxmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
186 xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y", xxmin, ymax, "l", xmin, ymax,
187 xmin, yymax, "y", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", "h", how, "Q",
188 }
189 elseif method == 1 then
190 list = {
191 "q", line, "w", xxmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
192 xmax, ymax, "l", xmin, ymax, "l", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y",
193 "h", how, "Q",
194 }
195 elseif method == 2 then
196 list = {
197 "q", line, "w", xxmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xxmin, ymax,
198 "l", xmin, ymax, xmin, yymax, "y", xmin, yymin, "l", xmin, ymin, xxmin, ymin,
199 "y", "h", how, "Q",
200 }
201 elseif method == 3 then
202 list = {
203 "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, yymax, "l", xmax, ymax,
204 xxmax, ymax, "y", xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y", xmin, ymin,
205 "l", "h", how, "Q",
206 }
207
208 elseif method == 4 then
209 list = {
210 "q", line, "w", xmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
211 xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y", xmin, ymax, "l", xmin, ymin, "l",
212 "h", how, "Q",
213 }
214 elseif method == 5 then
215 list = {
216 "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, yymax, "l", xmax, ymax,
217 xxmax, ymax, "y", xmin, ymax, "l", xmin, ymin, "l", "h", how, "Q",
218 }
219 elseif method == 6 then
220 list = {
221 "q", line, "w", xmin, ymin, "m", xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y",
222 xmax, ymax, "l", xmin, ymax, "l", xmin, ymin, "l", "h", how, "Q",
223 }
224 elseif method == 7 then
225 list = {
226 "q", line, "w", xxmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xmin, ymax,
227 "l", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", "h", how, "Q",
228 }
229 elseif method == 8 then
230 list = {
231 "q", line, "w", xmin, ymin, "m", xmax, ymin, "l", xmax, ymax, "l", xxmin, ymax,
232 "l", xmin, ymax, xmin, yymax, "y", xmin, ymin, "l", "h", how, "Q",
233 }
234 elseif method == 9 then
235 list = {
236 "q", line, "w", xmin, ymax, "m", xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y",
237 xxmax, ymin, "l", xmax, ymin, xmax, yymin, "y", xmax, ymax, "l", how, "Q",
238 }
239 elseif method == 10 then
240 list = {
241 "q", line, "w", xmax, ymax, "m", xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y",
242 xmin, yymin, "l", xmin, ymin, xxmin, ymin, "y", xmax, ymin, "l", how, "Q",
243 }
244 elseif method == 11 then
245 list = {
246 "q", line, "w", xmax, ymin, "m", xmax, yymax, "l", xmax, ymax, xxmax, ymax, "y",
247 xxmin, ymax, "l", xmin, ymax, xmin, yymax, "y", xmin, ymin, "l", how, "Q",
248 }
249 elseif method == 12 then
250 list = {
251 "q", line, "w", xmin, ymax, "m", xxmax, ymax, "l", xmax, ymax, xmax, yymax, "y",
252 xmax, yymin, "l", xmax, ymin, xxmax, ymin, "y", xmin, ymin, "l", how, "Q",
253 }
254 elseif method == 13 then
255 list = {
256 "q", line, "w", xmin, ymax, "m", xxmax, ymax, "l", xmax, ymax, xmax, yymax, "y",
257 xmax, ymin, "l", how, "Q",
258 }
259 elseif method == 14 then
260 list = {
261 "q", line, "w", xmax, ymax, "m", xmax, yymin, "l", xmax, ymin, xxmax, ymin, "y",
262 xmin, ymin, "l", how, "Q",
263 }
264 elseif method == 15 then
265 list = {
266 "q", line, "w", xmax, ymin, "m", xxmin, ymin, "l", xmin, ymin, xmin, yymin, "y",
267 xmin, ymax, "l", how, "Q",
268 }
269 elseif method == 16 then
270 list = {
271 "q", line, "w", xmin, ymin, "m", xmin, yymax, "l", xmin, ymax, xxmin, ymax, "y",
272 xmax, ymax, "l", how, "Q",
273 }
274 elseif method == 17 then
275 list = {
276 "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", how, "Q",
277 }
278 elseif method == 18 then
279 list = {
280 "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", how, "Q",
281 }
282 elseif method == 19 then
283 list = {
284 "q", line, "w", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y", how, "Q",
285 }
286 elseif method == 20 then
287 list = {
288 "q", line, "w", xmin, yymax, "m", xmin, ymax, xxmin, ymax, "y", how, "Q",
289 }
290 elseif method == 21 then
291 list = {
292 "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmin, yymax, "m",
293 xmin, ymax, xxmin, ymax, "y", how, "Q",
294 }
295 elseif method == 22 then
296 list = {
297 "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmax, yymin, "m",
298 xmax, ymin, xxmax, ymin, "y", how, "Q",
299 }
300 elseif method == 23 then
301 list = {
302 "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", xxmin, ymin, "m",
303 xmin, ymin, xmin, yymin, "y", how, "Q",
304 }
305 elseif method == 24 then
306 list = {
307 "q", line, "w", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y", xmin, yymax, "m",
308 xmin, ymax, xxmin, ymax, "y", how, "Q",
309 }
310 elseif method == 25 then
311 list = {
312 "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xmax, yymin, "m",
313 xmax, ymin, xxmax, ymin, "y", xxmin, ymin, "m", xmin, ymin, xmin, yymin, "y",
314 xmin, yymax, "m", xmin, ymax, xxmin, ymax, "y", how, "Q",
315 }
316 elseif method == 26 then
317 list = {
318 "q", line, "w", xmax, yymin, "m", xmax, ymin, xxmax, ymin, "y", xmin, yymax, "m",
319 xmin, ymax, xxmin, ymax, "y", how, "Q",
320 }
321
322 elseif method == 27 then
323 list = {
324 "q", line, "w", xxmax, ymax, "m", xmax, ymax, xmax, yymax, "y", xxmin, ymin, "m",
325 xmin, ymin, xmin, yymin, "y", how, "Q",
326 }
327 end
328 pdfprint("direct",concat(list," "))
329 end
330 end
331
332 local f_rectangle = formatters["%.6N w %.6N %.6N %.6N %.6N re %s"]
333 local f_baselined = formatters["%.6N w %.6N %.6N %.6N %.6N re s %.6N %.6N m %.6N %.6N l s"]
334 local f_dashlined = formatters["%.6N w %.6N %.6N %.6N %.6N re s [%.6N %.6N] 2 d %.6N %.6N m %.6N %.6N l s"]
335 local f_radtangle = formatters[
336[[%.6N w %.6N %.6N m
337%.6N %.6N l %.6N %.6N %.6N %.6N y
338%.6N %.6N l %.6N %.6N %.6N %.6N y
339%.6N %.6N l %.6N %.6N %.6N %.6N y
340%.6N %.6N l %.6N %.6N %.6N %.6N y
341h %s]]
342 ]
343
344 ruleactions.fill = function(p,h,v,i,n)
345 if p.corner then
346 return round(p,i)
347 else
348 local l = (p.line or 65536)*bpfactor
349 local r = p and (p.radius or 0)*bpfactor or 0
350 local w = h * bpfactor
351 local h = v * bpfactor
352 local m = nil
353 local t = i == "fill" and "f" or "s"
354 local o = l / 2
355 if r > 0 then
356 w = w - o
357 h = h - o
358 m = f_radtangle(l, r,o, w-r,o, w,o,w,r, w,h-r, w,h,w-r,h, r,h, o,h,o,h-r, o,r, o,o,r,o, t)
359 else
360 w = w - l
361 h = h - l
362 m = f_rectangle(l,o,o,w,h,t)
363 end
364 pdfprint("direct",m)
365 end
366 end
367
368 ruleactions.draw = ruleactions.fill
369 ruleactions.stroke = ruleactions.fill
370
371 ruleactions.box = function(p,h,v,i,n)
372 local w, h, d = getwhd(n)
373 local line = p.line or 65536
374 local l = line *bpfactor
375 local w = w * bpfactor
376 local h = h * bpfactor
377 local d = d * bpfactor
378 local o = l / 2
379 if (d >= 0 and h >= 0) or (d <= 0 and h <= 0) then
380 local dashed = tonumber(p.dashed)
381 if dashed and dashed > 5*line then
382 dashed = dashed * bpfactor
383 local delta = (w - 2*dashed*floor(w/(2*dashed)))/2
384 pdfprint("direct",f_dashlined(l,o,o,w-l,h+d-l,dashed,dashed,delta,d,w-delta,d))
385 else
386 pdfprint("direct",f_baselined(l,o,o,w-l,h+d-l,0,d,w,d))
387 end
388 else
389 pdfprint("direct",f_rectangle(l,o,o,w-l,h+d-l))
390 end
391 end
392
393end
394
395interfaces.implement {
396 name = "frule",
397 arguments = { {
398 { "width", "dimension" },
399 { "height", "dimension" },
400 { "depth", "dimension" },
401 { "radius", "dimension" },
402 { "line", "dimension" },
403 { "type", "string" },
404 { "data", "string" },
405 { "name", "string" },
406 { "radius", "dimension" },
407 { "corner", "string" },
408 } } ,
409 actions = function(t)
410 local rule = userrule(t)
411 if t.type == "mp" then
412 t.ma = getattribute(a_colormodel) or 1
413 t.ca = getattribute(a_color)
414 t.ta = getattribute(a_transparency)
415 else
416 setattrlist(rule,true)
417 end
418 context(tonode(rule))
419 end
420}
421
422interfaces.implement {
423 name = "outlinerule",
424 public = true,
425 protected = true,
426 arguments = { {
427 { "width", "dimension" },
428 { "height", "dimension" },
429 { "depth", "dimension" },
430 { "line", "dimension" },
431 } } ,
432 actions = function(t)
433 local rule = outlinerule(t.width,t.height,t.depth,t.line)
434 setattrlist(rule,true)
435 context(tonode(rule))
436 end
437}
438
439interfaces.implement {
440 name = "framedoutline",
441 arguments = { "dimension", "dimension", "dimension", "dimension" },
442 actions = function(w,h,d,l)
443 local rule = outlinerule(w,h,d,l)
444 setattrlist(rule,true)
445 context(tonode(rule))
446 end
447}
448
449interfaces.implement {
450 name = "fakeword",
451 arguments = { {
452 { "factor", "dimension" },
453 { "name", "string" },
454 { "min", "dimension" },
455 { "max", "dimension" },
456 { "n", "integer" },
457 } } ,
458 actions = function(t)
459 local factor = t.factor or 0
460 local amount = getrandom("fakeword",t.min,t.max)
461 local rule = userrule {
462 height = 1.25*factor,
463 depth = 0.25*factor,
464 width = floor(amount/10000) * 10000,
465 line = 0.10*factor,
466 ma = getattribute(a_colormodel) or 1,
467 ca = getattribute(a_color),
468 ta = getattribute(a_transparency),
469 type = "mp",
470 name = t.name,
471 }
472 setattrlist(rule,true)
473 context(tonode(rule))
474 end
475}
476 |