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

sile-typesetter / sile / 9304049654

30 May 2024 02:12PM UTC coverage: 60.021% (-14.7%) from 74.707%
9304049654

push

github

web-flow
Merge 1a26b4f22 into a1fd105f8

6743 of 12900 new or added lines in 186 files covered. (52.27%)

347 existing lines in 49 files now uncovered.

10311 of 17179 relevant lines covered (60.02%)

3307.34 hits per line

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

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

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

6
local enter = function (self, _)
7
   -- Probably broken, see:
8
   -- https://github.com/sile-typesetter/sile/issues/427
NEW
9
   if not self.rotate then
×
NEW
10
      return
×
11
   end
NEW
12
   if not SILE.outputter.enterFrameRotate then
×
NEW
13
      return SU.warn(
×
14
         "Frame '"
NEW
15
            .. self.id("' will not be rotated: backend '")
×
NEW
16
            .. SILE.outputter._name
×
NEW
17
            .. "' does not support rotation"
×
18
      )
19
   end
NEW
20
   local theta = -math.rad(self.rotate)
×
21
   -- Keep center point the same
NEW
22
   local x0 = self:left():tonumber()
×
NEW
23
   local x1 = x0 + math.sin(theta) * self:height():tonumber()
×
NEW
24
   local y0 = self:bottom():tonumber()
×
NEW
25
   SILE.outputter:enterFrameRotate(x0, x1, y0, theta) -- Unstable API
×
26
end
27

28
local leave = function (self, _)
NEW
29
   if not self.rotate then
×
NEW
30
      return
×
31
   end
NEW
32
   if not SILE.outputter.enterFrameRotate then
×
NEW
33
      return
×
34
   end -- no enter no leave.
NEW
35
   SILE.outputter:leaveFrameRotate()
×
36
end
37

38
-- What is the width, depth and height of a rectangle width w and height h rotated by angle theta?
39
-- rect1 = Rectangle[{0, 0}, {w, h}]
40
-- {{xmin, xmax}, {ymin, ymax}} = Refine[RegionBounds[TransformedRegion[rect1,
41
--                                                     RotationTransform[theta, {w/2,h/2}]]],
42
--                                      w > 0 && h > 0 && theta > 0 && theta < 2 Pi ]
43
-- PiecewiseExpand[xmax - xmin]
44
-- \[Piecewise]  -w Cos[theta]-h Sin[theta]  Sin[theta]<=0&&Cos[theta]<=0
45
--                w Cos[theta]-h Sin[theta]  Sin[theta]<=0&&Cos[theta]>0
46
--               -w Cos[theta]+h Sin[theta]  Sin[theta]>0&&Cos[theta]<=0
47
--                w Cos[theta]+h Sin[theta]  True
48

49
local outputRotatedHbox = function (self, typesetter, line)
NEW
50
   local origbox = self.value.orig
×
NEW
51
   local theta = self.value.theta
×
52

53
   -- Find origin of untransformed hbox
NEW
54
   local X = typesetter.frame.state.cursorX
×
NEW
55
   local Y = typesetter.frame.state.cursorY
×
NEW
56
   typesetter.frame.state.cursorX = X - (origbox.width.length - self.width) / 2
×
NEW
57
   local horigin = X + origbox.width.length / 2
×
NEW
58
   local vorigin = Y - (origbox.height - origbox.depth) / 2
×
59

NEW
60
   SILE.outputter:rotateFn(horigin, vorigin, theta, function ()
×
NEW
61
      origbox:outputYourself(typesetter, line)
×
62
   end)
NEW
63
   typesetter.frame.state.cursorX = X
×
NEW
64
   typesetter.frame.state.cursorY = Y
×
NEW
65
   typesetter.frame:advanceWritingDirection(self.width)
×
66
end
67

UNCOV
68
function package:_init ()
×
NEW
69
   base._init(self)
×
NEW
70
   if SILE.typesetter and SILE.typesetter.frame then
×
NEW
71
      enter(SILE.typesetter.frame, SILE.typesetter)
×
NEW
72
      table.insert(SILE.typesetter.frame.leaveHooks, leave)
×
73
   end
NEW
74
   table.insert(SILE.framePrototype.enterHooks, enter)
×
NEW
75
   table.insert(SILE.framePrototype.leaveHooks, leave)
×
76
end
77

UNCOV
78
function package:registerCommands ()
×
NEW
79
   self:registerCommand("rotate", function (options, content)
×
NEW
80
      if not SILE.outputter.rotateFn then
×
NEW
81
         SU.warn("Output will not be rotated: backend '" .. SILE.outputter._name .. "' does not support rotation")
×
NEW
82
         return SILE.process(content)
×
83
      end
NEW
84
      local angle = SU.required(options, "angle", "rotate command")
×
NEW
85
      local theta = -math.rad(angle)
×
NEW
86
      local origbox, hlist = SILE.typesetter:makeHbox(content)
×
NEW
87
      local h = origbox.height + origbox.depth
×
NEW
88
      local w = origbox.width.length
×
NEW
89
      local st = math.sin(theta)
×
NEW
90
      local ct = math.cos(theta)
×
91
      local height, width, depth
NEW
92
      if st <= 0 and ct <= 0 then
×
NEW
93
         width = -w * ct - h * st
×
NEW
94
         height = 0.5 * (h - h * ct - w * st)
×
NEW
95
         depth = 0.5 * (h + h * ct + w * st)
×
NEW
96
      elseif st <= 0 and ct > 0 then
×
NEW
97
         width = w * ct - h * st
×
NEW
98
         height = 0.5 * (h + h * ct - w * st)
×
NEW
99
         depth = 0.5 * (h - h * ct + w * st)
×
NEW
100
      elseif st > 0 and ct <= 0 then
×
NEW
101
         width = -w * ct + h * st
×
NEW
102
         height = 0.5 * (h - h * ct + w * st)
×
NEW
103
         depth = 0.5 * (h + h * ct - w * st)
×
104
      else
NEW
105
         width = w * ct + h * st
×
NEW
106
         height = 0.5 * (h + h * ct + w * st)
×
NEW
107
         depth = 0.5 * (h - h * ct - w * st)
×
108
      end
NEW
109
      depth = -depth
×
NEW
110
      if depth < SILE.types.length(0) then
×
NEW
111
         depth = SILE.types.length(0)
×
112
      end
NEW
113
      SILE.typesetter:pushHbox({
×
114
         value = { orig = origbox, theta = theta },
115
         height = height,
116
         width = width,
117
         depth = depth,
118
         outputYourself = outputRotatedHbox,
119
      })
NEW
120
      SILE.typesetter:pushHlist(hlist)
×
121
   end)
122
end
123

124
package.documentation = [[
125
\begin{document}
126
\use[module=packages.rotate]
127
The \autodoc:package{rotate} package allows you to rotate things. You can rotate entire
128
frames, by adding the \autodoc:parameter{rotate=<angle>} declaration to your frame declaration,
129
and you can rotate any content by issuing the command \autodoc:command{\rotate[angle=<angle>]{<content>}},
130
where the angle is measured in degrees.
131

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

138
The previous line was produced by the following code:
139

140
\begin[type=autodoc:codeblock]{raw}
141
here is some text rotated by
142
\rotate[angle=10]{ten}, \rotate[angle=20]{twenty}, and \rotate[angle=40]{forty} degrees.
143
\end{raw}
144
\end{document}
UNCOV
145
]]
×
146

UNCOV
147
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

© 2026 Coveralls, Inc