• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 6713098919

31 Oct 2023 10:21PM UTC coverage: 52.831% (-21.8%) from 74.636%
6713098919

push

github

web-flow
Merge d0a2a1ee9 into b185d4972

45 of 45 new or added lines in 3 files covered. (100.0%)

8173 of 15470 relevant lines covered (52.83%)

6562.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/packages/rotate/init.lua
1
local base = require("packages.base")
×
2

3
local package = pl.class(base)
×
4
package._name = "rotate"
×
5

6
local pdf = require("justenoughlibtexpdf")
×
7

8
local enter = function (self, _)
9
  if not self.rotate then return end
×
10
  local x = -math.rad(self.rotate)
×
11
  -- Keep center point the same
12
  pdf:gsave()
×
13
  local cx = self:left():tonumber()
×
14
  local cy = -self:bottom():tonumber()
×
15
  pdf.setmatrix(1, 0, 0, 1, cx + math.sin(x) * self:height():tonumber(), cy)
×
16
  pdf.setmatrix(math.cos(x), math.sin(x), -math.sin(x), math.cos(x), 0, 0)
×
17
  pdf.setmatrix(1, 0, 0, 1, -cx, -cy)
×
18
end
19

20
local leave =   function(self, _)
21
  if not self.rotate then return end
×
22
  pdf:grestore()
×
23
end
24

25
-- What is the width, depth and height of a rectangle width w and height h rotated by angle theta?
26
-- rect1 = Rectangle[{0, 0}, {w, h}]
27
-- {{xmin, xmax}, {ymin, ymax}} = Refine[RegionBounds[TransformedRegion[rect1,
28
--                                                     RotationTransform[theta, {w/2,h/2}]]],
29
--                                      w > 0 && h > 0 && theta > 0 && theta < 2 Pi ]
30
-- PiecewiseExpand[xmax - xmin]
31
    -- \[Piecewise]  -w Cos[theta]-h Sin[theta]  Sin[theta]<=0&&Cos[theta]<=0
32
    --                w Cos[theta]-h Sin[theta]  Sin[theta]<=0&&Cos[theta]>0
33
    --               -w Cos[theta]+h Sin[theta]  Sin[theta]>0&&Cos[theta]<=0
34
    --                w Cos[theta]+h Sin[theta]  True
35

36
local outputRotatedHbox = function (self, typesetter, line)
37
  local origbox = self.value.orig
×
38
  local x = self.value.theta
×
39
  -- Find origin of untransformed hbox
40
  local save = typesetter.frame.state.cursorX
×
41
  typesetter.frame.state.cursorX = typesetter.frame.state.cursorX - (origbox.width.length-self.width)/2
×
42

43
  local horigin = (typesetter.frame.state.cursorX + origbox.width.length / 2):tonumber()
×
44
  local vorigin = -(typesetter.frame.state.cursorY - (origbox.height - origbox.depth) / 2):tonumber()
×
45
  pdf:gsave()
×
46
  pdf.setmatrix(1, 0, 0, 1, horigin, vorigin)
×
47
  pdf.setmatrix(math.cos(x), math.sin(x), -math.sin(x), math.cos(x), 0, 0)
×
48
  pdf.setmatrix(1, 0, 0, 1, -horigin, -vorigin)
×
49
  origbox:outputYourself(typesetter, line)
×
50
  pdf:grestore()
×
51
  typesetter.frame.state.cursorX = save
×
52
  typesetter.frame:advanceWritingDirection(self.width)
×
53
end
54

55
function package:_init ()
×
56
  base._init(self)
×
57
  if SILE.typesetter and SILE.typesetter.frame then
×
58
    enter(SILE.typesetter.frame, SILE.typesetter)
×
59
    table.insert(SILE.typesetter.frame.leaveHooks, leave)
×
60
  end
61
  table.insert(SILE.framePrototype.enterHooks, enter)
×
62
  table.insert(SILE.framePrototype.leaveHooks, leave)
×
63
end
64

65
function package:registerCommands ()
×
66

67
  self:registerCommand("rotate", function(options, content)
×
68
    local angle = SU.required(options, "angle", "rotate command")
×
69
    local theta = -math.rad(angle)
×
70
    local origbox, hlist = SILE.typesetter:makeHbox(content)
×
71
    local h = origbox.height + origbox.depth
×
72
    local w = origbox.width.length
×
73
    local st = math.sin(theta)
×
74
    local ct = math.cos(theta)
×
75
    local height, width, depth
76
    if st <= 0 and ct <= 0    then
×
77
      width  = -w * ct - h * st
×
78
      height = 0.5*(h-h*ct-w*st)
×
79
      depth  = 0.5*(h+h*ct+w*st)
×
80
    elseif st <=0 and ct > 0  then
×
81
      width  =  w * ct - h * st
×
82
      height = 0.5*(h+h*ct-w*st)
×
83
      depth  = 0.5*(h-h*ct+w*st)
×
84
    elseif st > 0 and ct <= 0 then
×
85
      width  = -w * ct + h * st
×
86
      height = 0.5*(h-h*ct+w*st)
×
87
      depth  = 0.5*(h+h*ct-w*st)
×
88
    else
89
      width  =  w * ct + h * st
×
90
      height = 0.5*(h+h*ct+w*st)
×
91
      depth  = 0.5*(h-h*ct-w*st)
×
92
    end
93
    depth = -depth
×
94
    if depth < SILE.length(0) then depth = SILE.length(0) end
×
95
    SILE.outputter:_ensureInit()
×
96
    SILE.typesetter:pushHbox({
×
97
      value = { orig = origbox, theta = theta},
98
      height = height,
99
      width = width,
100
      depth = depth,
101
      outputYourself = outputRotatedHbox
×
102
    })
103
    SILE.typesetter:pushHlist(hlist)
×
104
  end)
105

106
end
107

108
package.documentation = [[
109
\begin{document}
110
\use[module=packages.rotate]
111
The \autodoc:package{rotate} package allows you to rotate things. You can rotate entire
112
frames, by adding the \autodoc:parameter{rotate=<angle>} declaration to your frame declaration,
113
and you can rotate any content by issuing the command \autodoc:command{\rotate[angle=<angle>]{<content>}},
114
where the angle is measured in degrees.
115

116
Content which is rotated is placed in a box and rotated. The height and width of
117
the rotated box is measured, and then put into the normal horizontal list for
118
typesetting. The effect is that space is reserved around the rotated content.
119
The best way to understand this is by example: here is some text rotated by
120
\rotate[angle=10]{ten}, \rotate[angle=20]{twenty}, and \rotate[angle=40]{forty} degrees.
121

122
The previous line was produced by the following code:
123

124
\begin[type=autodoc:codeblock]{raw}
125
here is some text rotated by
126
\rotate[angle=10]{ten}, \rotate[angle=20]{twenty}, and \rotate[angle=40]{forty} degrees.
127
\end{raw}
128
\end{document}
129
]]
×
130

131
return package
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc