• No results found

1 l3draw implementation

N/A
N/A
Protected

Academic year: 2022

Share "1 l3draw implementation"

Copied!
63
0
0

Full text

(1)

File I

Implementation

1 l3draw implementation

1 ⟨∗package⟩

2 ⟨@@=draw⟩

3 \ProvidesExplPackage{l3draw}{2022-04-20}{}

4 {L3 Experimental core drawing support}

1.1 Internal auxiliaries

\s__draw_mark

\s__draw_stop

Internal scan marks.

5 \scan_new:N \s__draw_mark

6 \scan_new:N \s__draw_stop

(End definition for\s__draw_mark and\s__draw_stop.)

\q__draw_recursion_tail

\q__draw_recursion_stop

Internal recursion quarks.

7 \quark_new:N \q__draw_recursion_tail

8 \quark_new:N \q__draw_recursion_stop

(End definition for\q__draw_recursion_tail and\q__draw_recursion_stop.)

\__draw_if_recursion_tail_stop_do:Nn Functions to query recursion quarks.

9 \__kernel_quark_new_test:N \__draw_if_recursion_tail_stop_do:Nn (End definition for\__draw_if_recursion_tail_stop_do:Nn.)

Everything else is in the sub-files!

10 ⟨/package⟩

2 l3draw-boxes implementation

11 ⟨∗package⟩

12 ⟨@@=draw⟩

Inserting boxes requires us to “interrupt” the drawing state, so is closely linked to scoping. At the same time, there are a few additional features required to make text work in a flexible way.

\l__draw_tmp_box

13 \box_new:N \l__draw_tmp_box (End definition for\l__draw_tmp_box.)

\draw_box_use:N

\__draw_box_use:Nnnnn

Before inserting a box, we need to make sure that the bounding box is being updated correctly. As drawings track transformations as a whole, rather than as separate opera- tions, we do the insertion using an almost-raw matrix. The process is split into two so that coffins are also supported.

14 \cs_new_protected:Npn \draw_box_use:N #1

15 {

(2)

16 \__draw_box_use:Nnnnn #1

17 { 0pt } { -\box_dp:N #1 } { \box_wd:N #1 } { \box_ht:N #1 }

18 }

19 \cs_new_protected:Npn \__draw_box_use:Nnnnn #1#2#3#4#5

20 {

21 \bool_if:NT \l_draw_bb_update_bool

22 {

23 \__draw_point_process:nn

24 { \__draw_path_update_limits:nn }

25 { \draw_point_transform:n { #2 , #3 } }

26 \__draw_point_process:nn

27 { \__draw_path_update_limits:nn }

28 { \draw_point_transform:n { #4 , #3 } }

29 \__draw_point_process:nn

30 { \__draw_path_update_limits:nn }

31 { \draw_point_transform:n { #4 , #5 } }

32 \__draw_point_process:nn

33 { \__draw_path_update_limits:nn }

34 { \draw_point_transform:n { #2 , #5 } }

35 }

36 \group_begin:

37 \hbox_set:Nn \l__draw_tmp_box

38 {

39 \use:x

40 {

41 \__draw_backend_box_use:Nnnnn #1

42 { \fp_use:N \l__draw_matrix_a_fp }

43 { \fp_use:N \l__draw_matrix_b_fp }

44 { \fp_use:N \l__draw_matrix_c_fp }

45 { \fp_use:N \l__draw_matrix_d_fp }

46 }

47 }

48 \hbox_set:Nn \l__draw_tmp_box

49 {

50 \__kernel_kern:n { \l__draw_xshift_dim }

51 \box_move_up:nn { \l__draw_yshift_dim }

52 { \box_use_drop:N \l__draw_tmp_box }

53 }

54 \box_set_ht:Nn \l__draw_tmp_box { 0pt }

55 \box_set_dp:Nn \l__draw_tmp_box { 0pt }

56 \box_set_wd:Nn \l__draw_tmp_box { 0pt }

57 \box_use_drop:N \l__draw_tmp_box

58 \group_end:

59 }

(End definition for\draw_box_use:N and\__draw_box_use:Nnnnn. This function is documented on page

??.)

\draw_coffin_use:Nnn Slightly more than a shortcut: we have to allow for the fact that coffins have no apparent width before the reference point.

60 \cs_new_protected:Npn \draw_coffin_use:Nnn #1#2#3

61 {

62 \group_begin:

63 \hbox_set:Nn \l__draw_tmp_box

(3)

64 { \coffin_typeset:Nnnnn #1 {#2} {#3} { 0pt } { 0pt } }

65 \__draw_box_use:Nnnnn \l__draw_tmp_box

66 { \box_wd:N \l__draw_tmp_box - \coffin_wd:N #1 }

67 { -\box_dp:N \l__draw_tmp_box }

68 { \box_wd:N \l__draw_tmp_box }

69 { \box_ht:N \l__draw_tmp_box }

70 \group_end:

71 }

(End definition for\draw_coffin_use:Nnn. This function is documented on page??.)

72 ⟨/package⟩

3 l3draw-layers implementation

73 ⟨∗package⟩

74 ⟨@@=draw⟩

3.1 User interface

\draw_layer_new:n

75 \cs_new_protected:Npn \draw_layer_new:n #1

76 {

77 \str_if_eq:nnTF {#1} { main }

78 { \msg_error:nnn { draw } { main-reserved } }

79 {

80 \box_new:c { g__draw_layer_ #1 _box }

81 \box_new:c { l__draw_layer_ #1 _box }

82 }

83 }

(End definition for\draw_layer_new:n. This function is documented on page??.)

\l__draw_layer_tl The name of the current layer: we start off withmain.

84 \tl_new:N \l__draw_layer_tl

85 \tl_set:Nn \l__draw_layer_tl { main } (End definition for\l__draw_layer_tl.)

\l__draw_layer_close_bool Used to track if a layer needs to be closed.

86 \bool_new:N \l__draw_layer_close_bool (End definition for\l__draw_layer_close_bool.)

\l_draw_layers_clist

\g__draw_layers_clist

The list of layers to use starts off with just themain one.

87 \clist_new:N \l_draw_layers_clist

88 \clist_set:Nn \l_draw_layers_clist { main }

89 \clist_new:N \g__draw_layers_clist

(End definition for \l_draw_layers_clist and \g__draw_layers_clist. This variable is documented on page??.)

(4)

\draw_layer_begin:n

\draw_layer_end:

Layers may be called multiple times and have to work when nested. That drives a bit of grouping to get everything in order. Layers have to be zero width, so they get set as we go along.

90 \cs_new_protected:Npn \draw_layer_begin:n #1

91 {

92 \group_begin:

93 \box_if_exist:cTF { g__draw_layer_ #1 _box }

94 {

95 \str_if_eq:VnTF \l__draw_layer_tl {#1}

96 { \bool_set_false:N \l__draw_layer_close_bool }

97 {

98 \bool_set_true:N \l__draw_layer_close_bool

99 \tl_set:Nn \l__draw_layer_tl {#1}

100 \box_gset_wd:cn { g__draw_layer_ #1 _box } { 0pt }

101 \hbox_gset:cw { g__draw_layer_ #1 _box }

102 \box_use_drop:c { g__draw_layer_ #1 _box }

103 \group_begin:

104 }

105 \draw_linewidth:n { \l_draw_default_linewidth_dim }

106 }

107 {

108 \str_if_eq:nnTF {#1} { main }

109 { \msg_error:nnn { draw } { unknown-layer } {#1} }

110 { \msg_error:nnn { draw } { main-layer } }

111 }

112 }

113 \cs_new_protected:Npn \draw_layer_end:

114 {

115 \bool_if:NT \l__draw_layer_close_bool

116 {

117 \group_end:

118 \hbox_gset_end:

119 }

120 \group_end:

121 }

(End definition for\draw_layer_begin:n and\draw_layer_end:. These functions are documented on page??.)

3.2 Internal cross-links

\__draw_layers_insert: Themainlayer is special, otherwise just dump the layer box inside a scope.

122 \cs_new_protected:Npn \__draw_layers_insert:

123 {

124 \clist_map_inline:Nn \l_draw_layers_clist

125 {

126 \str_if_eq:nnTF {##1} { main }

127 {

128 \box_set_wd:Nn \l__draw_layer_main_box { 0pt }

129 \box_use_drop:N \l__draw_layer_main_box

130 }

131 {

132 \__draw_backend_scope_begin:

133 \box_gset_wd:cn { g__draw_layer_ ##1 _box } { 0pt }

(5)

134 \box_use_drop:c { g__draw_layer_ ##1 _box }

135 \__draw_backend_scope_end:

136 }

137 }

138 }

(End definition for\__draw_layers_insert:.)

\__draw_layers_save:

\__draw_layers_restore:

Simple save/restore functions.

139 \cs_new_protected:Npn \__draw_layers_save:

140 {

141 \clist_map_inline:Nn \l_draw_layers_clist

142 {

143 \str_if_eq:nnF {##1} { main }

144 {

145 \box_set_eq:cc { l__draw_layer_ ##1 _box }

146 { g__draw_layer_ ##1 _box }

147 }

148 }

149 }

150 \cs_new_protected:Npn \__draw_layers_restore:

151 {

152 \clist_map_inline:Nn \l_draw_layers_clist

153 {

154 \str_if_eq:nnF {##1} { main }

155 {

156 \box_gset_eq:cc { g__draw_layer_ ##1 _box }

157 { l__draw_layer_ ##1 _box }

158 }

159 }

160 }

(End definition for\__draw_layers_save: and\__draw_layers_restore:.)

161 \msg_new:nnnn { draw } { main-layer }

162 { Material~cannot~be~added~to~’main’~layer. }

163 { The~main~layer~may~only~be~accessed~at~the~top~level. }

164 \msg_new:nnn { draw } { main-reserved }

165 { The~’main’~layer~is~reserved. }

166 \msg_new:nnnn { draw } { unknown-layer }

167 { Layer~’#1’~has~not~been~created. }

168 { You~have~tried~to~use~layer~’#1’,~but~it~was~never~set~up. }

169 % \end{macrocode}

170 %

171 % \begin{macrocode}

172 ⟨/package⟩

4 l3draw-paths implementation

173 ⟨∗package⟩

174 ⟨@@=draw⟩

This sub-module covers more-or-less the same ideas aspgfcorepathconstruct.code.tex, though using the expandable FPU means that the implementation often varies. At present, equivalents of the following are currently absent:

(6)

• \pgfpatharcto,\pgfpatharctoprecomputed: These are extremely specialised and are very complex in implementation. If the functionality is required, it is likely that it will be set up from scratch here.

• \pgfpathparabola: Seems to be unused other than defining a TikZ interface, which itself is then not used further.

• \pgfpathsine,\pgfpathcosine: Need to see exactly how these need to work, in particular whether a wider input range is needed and what approximation to make.

• \pgfpathcurvebetweentime,\pgfpathcurvebetweentimecontinue: These don’t seem to be used at all.

\l__draw_path_tmp_tl

\l__draw_path_tmpa_fp

\l__draw_path_tmpb_fp

Scratch space.

175 \tl_new:N \l__draw_path_tmp_tl

176 \fp_new:N \l__draw_path_tmpa_fp

177 \fp_new:N \l__draw_path_tmpb_fp

(End definition for\l__draw_path_tmp_tl,\l__draw_path_tmpa_fp, and\l__draw_path_tmpb_fp.)

4.1 Tracking paths

\g__draw_path_lastx_dim

\g__draw_path_lasty_dim

The last point visited on a path.

178 \dim_new:N \g__draw_path_lastx_dim

179 \dim_new:N \g__draw_path_lasty_dim

(End definition for\g__draw_path_lastx_dim and\g__draw_path_lasty_dim.)

\g__draw_path_xmax_dim

\g__draw_path_xmin_dim

\g__draw_path_ymax_dim

\g__draw_path_ymin_dim

The limiting size of a path.

180 \dim_new:N \g__draw_path_xmax_dim

181 \dim_new:N \g__draw_path_xmin_dim

182 \dim_new:N \g__draw_path_ymax_dim

183 \dim_new:N \g__draw_path_ymin_dim

(End definition for\g__draw_path_xmax_dim and others.)

\__draw_path_update_limits:nn

\__draw_path_reset_limits:

Track the limits of a path and (perhaps) of the picture as a whole. (At present the latter is always true: that will change as more complex functionality is added.)

184 \cs_new_protected:Npn \__draw_path_update_limits:nn #1#2

185 {

186 \dim_gset:Nn \g__draw_path_xmax_dim

187 { \dim_max:nn \g__draw_path_xmax_dim {#1} }

188 \dim_gset:Nn \g__draw_path_xmin_dim

189 { \dim_min:nn \g__draw_path_xmin_dim {#1} }

190 \dim_gset:Nn \g__draw_path_ymax_dim

191 { \dim_max:nn \g__draw_path_ymax_dim {#2} }

192 \dim_gset:Nn \g__draw_path_ymin_dim

193 { \dim_min:nn \g__draw_path_ymin_dim {#2} }

194 \bool_if:NT \l_draw_bb_update_bool

195 {

196 \dim_gset:Nn \g__draw_xmax_dim

197 { \dim_max:nn \g__draw_xmax_dim {#1} }

198 \dim_gset:Nn \g__draw_xmin_dim

199 { \dim_min:nn \g__draw_xmin_dim {#1} }

(7)

200 \dim_gset:Nn \g__draw_ymax_dim

201 { \dim_max:nn \g__draw_ymax_dim {#2} }

202 \dim_gset:Nn \g__draw_ymin_dim

203 { \dim_min:nn \g__draw_ymin_dim {#2} }

204 }

205 }

206 \cs_new_protected:Npn \__draw_path_reset_limits:

207 {

208 \dim_gset:Nn \g__draw_path_xmax_dim { -\c_max_dim }

209 \dim_gset:Nn \g__draw_path_xmin_dim { \c_max_dim }

210 \dim_gset:Nn \g__draw_path_ymax_dim { -\c_max_dim }

211 \dim_gset:Nn \g__draw_path_ymin_dim { \c_max_dim }

212 }

(End definition for\__draw_path_update_limits:nn and\__draw_path_reset_limits:.)

\__draw_path_update_last:nn A simple auxiliary to avoid repetition.

213 \cs_new_protected:Npn \__draw_path_update_last:nn #1#2

214 {

215 \dim_gset:Nn \g__draw_path_lastx_dim {#1}

216 \dim_gset:Nn \g__draw_path_lasty_dim {#2}

217 }

(End definition for\__draw_path_update_last:nn.)

4.2 Corner arcs

At the level of pathconstruction, rounded corners are handled by inserting a marker into the path: that is then picked up once the full path is constructed. Thus we need to set up the appropriate data structures here, such that this can be applied every time it is relevant.

\l__draw_corner_xarc_dim

\l__draw_corner_yarc_dim

The two arcs in use.

218 \dim_new:N \l__draw_corner_xarc_dim

219 \dim_new:N \l__draw_corner_yarc_dim

(End definition for\l__draw_corner_xarc_dim and\l__draw_corner_yarc_dim.)

\l__draw_corner_arc_bool A flag to speed up the repeated checks.

220 \bool_new:N \l__draw_corner_arc_bool (End definition for\l__draw_corner_arc_bool.)

\draw_path_corner_arc:nn Calculate the arcs, check they are non-zero.

221 \cs_new_protected:Npn \draw_path_corner_arc:nn #1#2

222 {

223 \dim_set:Nn \l__draw_corner_xarc_dim {#1}

224 \dim_set:Nn \l__draw_corner_yarc_dim {#2}

225 \bool_lazy_and:nnTF

226 { \dim_compare_p:nNn \l__draw_corner_xarc_dim = { 0pt } }

227 { \dim_compare_p:nNn \l__draw_corner_yarc_dim = { 0pt } }

228 { \bool_set_false:N \l__draw_corner_arc_bool }

229 { \bool_set_true:N \l__draw_corner_arc_bool }

230 }

(8)

(End definition for\draw_path_corner_arc:nn. This function is documented on page??.)

\__draw_path_mark_corner: Mark up corners for arc post-processing.

231 \cs_new_protected:Npn \__draw_path_mark_corner:

232 {

233 \bool_if:NT \l__draw_corner_arc_bool

234 {

235 \__draw_softpath_roundpoint:VV

236 \l__draw_corner_xarc_dim

237 \l__draw_corner_yarc_dim

238 }

239 }

(End definition for\__draw_path_mark_corner:.)

4.3 Basic path constructions

\draw_path_moveto:n

\draw_path_lineto:n

\__draw_path_moveto:nn

\__draw_path_lineto:nn

\draw_path_curveto:nnn

\__draw_path_curveto:nnnnnn

At present, stick to purely linear transformation support and skip the soft path business:

that will likely need to be revisited later.

240 \cs_new_protected:Npn \draw_path_moveto:n #1

241 {

242 \__draw_point_process:nn

243 { \__draw_path_moveto:nn }

244 { \draw_point_transform:n {#1} }

245 }

246 \cs_new_protected:Npn \__draw_path_moveto:nn #1#2

247 {

248 \__draw_path_update_limits:nn {#1} {#2}

249 \__draw_softpath_moveto:nn {#1} {#2}

250 \__draw_path_update_last:nn {#1} {#2}

251 }

252 \cs_new_protected:Npn \draw_path_lineto:n #1

253 {

254 \__draw_point_process:nn

255 { \__draw_path_lineto:nn }

256 { \draw_point_transform:n {#1} }

257 }

258 \cs_new_protected:Npn \__draw_path_lineto:nn #1#2

259 {

260 \__draw_path_mark_corner:

261 \__draw_path_update_limits:nn {#1} {#2}

262 \__draw_softpath_lineto:nn {#1} {#2}

263 \__draw_path_update_last:nn {#1} {#2}

264 }

265 \cs_new_protected:Npn \draw_path_curveto:nnn #1#2#3

266 {

267 \__draw_point_process:nnnn

268 {

269 \__draw_path_mark_corner:

270 \__draw_path_curveto:nnnnnn

271 }

272 { \draw_point_transform:n {#1} }

273 { \draw_point_transform:n {#2} }

274 { \draw_point_transform:n {#3} }

(9)

275 }

276 \cs_new_protected:Npn \__draw_path_curveto:nnnnnn #1#2#3#4#5#6

277 {

278 \__draw_path_update_limits:nn {#1} {#2}

279 \__draw_path_update_limits:nn {#3} {#4}

280 \__draw_path_update_limits:nn {#5} {#6}

281 \__draw_softpath_curveto:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}

282 \__draw_path_update_last:nn {#5} {#6}

283 }

(End definition for\draw_path_moveto:n and others. These functions are documented on page??.)

\draw_path_close: A simple wrapper.

284 \cs_new_protected:Npn \draw_path_close:

285 {

286 \__draw_path_mark_corner:

287 \__draw_softpath_closepath:

288 }

(End definition for\draw_path_close:. This function is documented on page??.)

4.4 Canvas path constructions

\draw_path_canvas_moveto:n

\draw_path_canvas_lineto:n

\draw_path_canvas_curveto:nnn

Operations with no application of the transformation matrix.

289 \cs_new_protected:Npn \draw_path_canvas_moveto:n #1

290 { \__draw_point_process:nn { \__draw_path_moveto:nn } {#1} }

291 \cs_new_protected:Npn \draw_path_canvas_lineto:n #1

292 { \__draw_point_process:nn { \__draw_path_lineto:nn } {#1} }

293 \cs_new_protected:Npn \draw_path_canvas_curveto:nnn #1#2#3

294 {

295 \__draw_point_process:nnnn

296 {

297 \__draw_path_mark_corner:

298 \__draw_path_curveto:nnnnnn

299 }

300 {#1} {#2} {#3}

301 }

(End definition for \draw_path_canvas_moveto:n, \draw_path_canvas_lineto:n, and \draw_path_- canvas_curveto:nnn. These functions are documented on page??.)

4.5 Computed curves

More complex operations need some calculations. To assist with those, various constants are pre-defined.

\draw_path_curveto:nn

\__draw_path_curveto:nnnn

\c__draw_path_curveto_a_fp

\c__draw_path_curveto_b_fp

A quadratic curve with one control point (xc, yc). The two required control points are then

x1= 1 3xs+2

3xc y1= 1 3ys+2

3yc and

x2= 1 3xe+2

3xc x2=1 3ye+2

3yc

using the start (last) point (xs, ys) and the end point (xs, ys).

(10)

302 \cs_new_protected:Npn \draw_path_curveto:nn #1#2

303 {

304 \__draw_point_process:nnn

305 { \__draw_path_curveto:nnnn }

306 { \draw_point_transform:n {#1} }

307 { \draw_point_transform:n {#2} }

308 }

309 \cs_new_protected:Npn \__draw_path_curveto:nnnn #1#2#3#4

310 {

311 \fp_set:Nn \l__draw_path_tmpa_fp { \c__draw_path_curveto_b_fp * #1 }

312 \fp_set:Nn \l__draw_path_tmpb_fp { \c__draw_path_curveto_b_fp * #2 }

313 \use:x

314 {

315 \__draw_path_mark_corner:

316 \__draw_path_curveto:nnnnnn

317 {

318 \fp_to_dim:n

319 {

320 \c__draw_path_curveto_a_fp * \g__draw_path_lastx_dim

321 + \l__draw_path_tmpa_fp

322 }

323 }

324 {

325 \fp_to_dim:n

326 {

327 \c__draw_path_curveto_a_fp * \g__draw_path_lasty_dim

328 + \l__draw_path_tmpb_fp

329 }

330 }

331 {

332 \fp_to_dim:n

333 { \c__draw_path_curveto_a_fp * #3 + \l__draw_path_tmpa_fp }

334 }

335 {

336 \fp_to_dim:n

337 { \c__draw_path_curveto_a_fp * #4 + \l__draw_path_tmpb_fp }

338 }

339 {#3}

340 {#4}

341 }

342 }

343 \fp_const:Nn \c__draw_path_curveto_a_fp { 1 / 3 }

344 \fp_const:Nn \c__draw_path_curveto_b_fp { 2 / 3 }

(End definition for\draw_path_curveto:nn and others. This function is documented on page??.)

\draw_path_arc:nnn

\draw_path_arc:nnnn

\__draw_path_arc:nnnn

\__draw_path_arc:nnNnn

\__draw_path_arc_auxi:nnnnNnn

\__draw_path_arc_auxi:fnnnNnn

\__draw_path_arc_auxi:fnfnNnn

\__draw_path_arc_auxii:nnnNnnnn

\__draw_path_arc_auxiii:nn

\__draw_path_arc_auxiv:nnnn

\__draw_path_arc_auxv:nn

\__draw_path_arc_auxvi:nn

\__draw_path_arc_add:nnnn

\l__draw_path_arc_delta_fp

\l__draw_path_arc_start_fp

\c__draw_path_arc_90_fp

Drawing an arc means dividing the total curve required into sections: using Bézier curves we can cover at most 90at once. To allow for later manipulations, we aim to have roughly equal last segments to the line, with the split set at a final part of 115.

345 \cs_new_protected:Npn \draw_path_arc:nnn #1#2#3

346 { \draw_path_arc:nnnn {#1} {#2} {#3} {#3} }

347 \cs_new_protected:Npn \draw_path_arc:nnnn #1#2#3#4

348 {

349 \use:x

10

(11)

350 {

351 \__draw_path_arc:nnnn

352 { \fp_eval:n {#1} }

353 { \fp_eval:n {#2} }

354 { \fp_to_dim:n {#3} }

355 { \fp_to_dim:n {#4} }

356 }

357 }

358 \cs_new_protected:Npn \__draw_path_arc:nnnn #1#2#3#4

359 {

360 \fp_compare:nNnTF {#1} > {#2}

361 { \__draw_path_arc:nnNnn {#1} {#2} - {#3} {#4} }

362 { \__draw_path_arc:nnNnn {#1} {#2} + {#3} {#4} }

363 }

364 \cs_new_protected:Npn \__draw_path_arc:nnNnn #1#2#3#4#5

365 {

366 \fp_set:Nn \l__draw_path_arc_start_fp {#1}

367 \fp_set:Nn \l__draw_path_arc_delta_fp { abs( #1 - #2 ) }

368 \fp_while_do:nNnn { \l__draw_path_arc_delta_fp } > { 90 }

369 {

370 \fp_compare:nNnTF \l__draw_path_arc_delta_fp > { 115 }

371 {

372 \__draw_path_arc_auxi:ffnnNnn

373 { \fp_to_decimal:N \l__draw_path_arc_start_fp }

374 { \fp_eval:n { \l__draw_path_arc_start_fp #3 90 } }

375 { 90 } {#2}

376 #3 {#4} {#5}

377 }

378 {

379 \__draw_path_arc_auxi:ffnnNnn

380 { \fp_to_decimal:N \l__draw_path_arc_start_fp }

381 { \fp_eval:n { \l__draw_path_arc_start_fp #3 60 } }

382 { 60 } {#2}

383 #3 {#4} {#5}

384 }

385 }

386 \__draw_path_mark_corner:

387 \__draw_path_arc_auxi:fnfnNnn

388 { \fp_to_decimal:N \l__draw_path_arc_start_fp }

389 {#2}

390 { \fp_eval:n { abs( \l__draw_path_arc_start_fp - #2 ) } }

391 {#2}

392 #3 {#4} {#5}

393 }

The auxiliary is responsible for calculating the required points. The “magic” number required to determine the length of the control vectors is well-established for a right- angle: 43(√

2−1) = 0.552 284 75. For other cases, we follow the calculation used by pgf but with the second common case of 60 pre-calculated for speed.

394 \cs_new_protected:Npn \__draw_path_arc_auxi:nnnnNnn #1#2#3#4#5#6#7

395 {

396 \use:x

397 {

398 \__draw_path_arc_auxii:nnnNnnnn

(12)

399 {#1} {#2} {#4} #5 {#6} {#7}

400 {

401 \fp_to_dim:n

402 {

403 \cs_if_exist_use:cF

404 { c__draw_path_arc_ #3 _fp }

405 { 4/3 * tand( 0.25 * #3 ) }

406 * #6

407 }

408 }

409 {

410 \fp_to_dim:n

411 {

412 \cs_if_exist_use:cF

413 { c__draw_path_arc_ #3 _fp }

414 { 4/3 * tand( 0.25 * #3 ) }

415 * #7

416 }

417 }

418 }

419 }

420 \cs_generate_variant:Nn \__draw_path_arc_auxi:nnnnNnn { fnf , ff }

We can now calculate the required points. As everything here is non-expandable, that is best done by using x-type expansion to build up the tokens. The three points are calculated out-of-order, since finding the second control point needs the position of the end point. Once the points are found, fire-off the fundamental path operation and update the record of where we are up to. The final point has to be

421 \cs_new_protected:Npn \__draw_path_arc_auxii:nnnNnnnn #1#2#3#4#5#6#7#8

422 {

423 \tl_clear:N \l__draw_path_tmp_tl

424 \__draw_point_process:nn

425 { \__draw_path_arc_auxiii:nn }

426 {

427 \__draw_point_transform_noshift:n

428 { \draw_point_polar:nnn {#7} {#8} { #1 #4 90 } }

429 }

430 \__draw_point_process:nnn

431 { \__draw_path_arc_auxiv:nnnn }

432 {

433 \draw_point_transform:n

434 { \draw_point_polar:nnn {#5} {#6} {#1} }

435 }

436 {

437 \draw_point_transform:n

438 { \draw_point_polar:nnn {#5} {#6} {#2} }

439 }

440 \__draw_point_process:nn

441 { \__draw_path_arc_auxv:nn }

442 {

443 \__draw_point_transform_noshift:n

444 { \draw_point_polar:nnn {#7} {#8} { #2 #4 -90 } }

445 }

446 \exp_after:wN \__draw_path_curveto:nnnnnn \l__draw_path_tmp_tl

(13)

447 \fp_set:Nn \l__draw_path_arc_delta_fp { abs ( #2 - #3 ) }

448 \fp_set:Nn \l__draw_path_arc_start_fp {#2}

449 }

The first control point.

450 \cs_new_protected:Npn \__draw_path_arc_auxiii:nn #1#2

451 {

452 \__draw_path_arc_aux_add:nn

453 { \g__draw_path_lastx_dim + #1 }

454 { \g__draw_path_lasty_dim + #2 }

455 }

The end point: simple arithmetic.

456 \cs_new_protected:Npn \__draw_path_arc_auxiv:nnnn #1#2#3#4

457 {

458 \__draw_path_arc_aux_add:nn

459 { \g__draw_path_lastx_dim - #1 + #3 }

460 { \g__draw_path_lasty_dim - #2 + #4 }

461 }

The second control point: extract the last point, do some rearrangement and record.

462 \cs_new_protected:Npn \__draw_path_arc_auxv:nn #1#2

463 {

464 \exp_after:wN \__draw_path_arc_auxvi:nn

465 \l__draw_path_tmp_tl {#1} {#2}

466 }

467 \cs_new_protected:Npn \__draw_path_arc_auxvi:nn #1#2#3#4#5#6

468 {

469 \tl_set:Nn \l__draw_path_tmp_tl { {#1} {#2} }

470 \__draw_path_arc_aux_add:nn

471 { #5 + #3 }

472 { #6 + #4 }

473 \tl_put_right:Nn \l__draw_path_tmp_tl { {#3} {#4} }

474 }

475 \cs_new_protected:Npn \__draw_path_arc_aux_add:nn #1#2

476 {

477 \tl_put_right:Nx \l__draw_path_tmp_tl

478 { { \fp_to_dim:n {#1} } { \fp_to_dim:n {#2} } }

479 }

480 \fp_new:N \l__draw_path_arc_delta_fp

481 \fp_new:N \l__draw_path_arc_start_fp

482 \fp_const:cn { c__draw_path_arc_90_fp } { 4/3 * (sqrt(2) - 1) }

483 \fp_const:cn { c__draw_path_arc_60_fp } { 4/3 * tand(15) }

(End definition for\draw_path_arc:nnn and others. These functions are documented on page??.)

\draw_path_arc_axes:nnnn A simple wrapper.

484 \cs_new_protected:Npn \draw_path_arc_axes:nnnn #1#2#3#4

485 {

486 \draw_transform_triangle:nnn { 0cm , 0cm } {#3} {#4}

487 \draw_path_arc:nnn {#1} {#2} { 1pt }

488 }

(End definition for\draw_path_arc_axes:nnnn. This function is documented on page??.)

(14)

\draw_path_ellipse:nnn

\__draw_path_ellipse:nnnnnn

\__draw_path_ellipse_arci:nnnnnn

\__draw_path_ellipse_arcii:nnnnnn

\__draw_path_ellipse_arciii:nnnnnn

\__draw_path_ellipse_arciv:nnnnnn

\c__draw_path_ellipse_fp

Drawing an ellipse is an optimised version of drawing an arc, in particular reusing the same constant. We need to deal with the ellipse in four parts and also deal with moving to the right place, closing it and ending up back at the center. That is handled on a per-arc basis, each in a separate auxiliary for readability.

489 \cs_new_protected:Npn \draw_path_ellipse:nnn #1#2#3

490 {

491 \__draw_point_process:nnnn

492 { \__draw_path_ellipse:nnnnnn }

493 { \draw_point_transform:n {#1} }

494 { \__draw_point_transform_noshift:n {#2} }

495 { \__draw_point_transform_noshift:n {#3} }

496 }

497 \cs_new_protected:Npn \__draw_path_ellipse:nnnnnn #1#2#3#4#5#6

498 {

499 \use:x

500 {

501 \__draw_path_moveto:nn

502 { \fp_to_dim:n { #1 + #3 } } { \fp_to_dim:n { #2 + #4 } }

503 \__draw_path_ellipse_arci:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}

504 \__draw_path_ellipse_arcii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}

505 \__draw_path_ellipse_arciii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}

506 \__draw_path_ellipse_arciv:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6}

507 }

508 \__draw_softpath_closepath:

509 \__draw_path_moveto:nn {#1} {#2}

510 }

511 \cs_new:Npn \__draw_path_ellipse_arci:nnnnnn #1#2#3#4#5#6

512 {

513 \__draw_path_curveto:nnnnnn

514 { \fp_to_dim:n { #1 + #3 + #5 * \c__draw_path_ellipse_fp } }

515 { \fp_to_dim:n { #2 + #4 + #6 * \c__draw_path_ellipse_fp } }

516 { \fp_to_dim:n { #1 + #3 * \c__draw_path_ellipse_fp + #5 } }

517 { \fp_to_dim:n { #2 + #4 * \c__draw_path_ellipse_fp + #6 } }

518 { \fp_to_dim:n { #1 + #5 } }

519 { \fp_to_dim:n { #2 + #6 } }

520 }

521 \cs_new:Npn \__draw_path_ellipse_arcii:nnnnnn #1#2#3#4#5#6

522 {

523 \__draw_path_curveto:nnnnnn

524 { \fp_to_dim:n { #1 - #3 * \c__draw_path_ellipse_fp + #5 } }

525 { \fp_to_dim:n { #2 - #4 * \c__draw_path_ellipse_fp + #6 } }

526 { \fp_to_dim:n { #1 - #3 + #5 * \c__draw_path_ellipse_fp } }

527 { \fp_to_dim:n { #2 - #4 + #6 * \c__draw_path_ellipse_fp } }

528 { \fp_to_dim:n { #1 - #3 } }

529 { \fp_to_dim:n { #2 - #4 } }

530 }

531 \cs_new:Npn \__draw_path_ellipse_arciii:nnnnnn #1#2#3#4#5#6

532 {

533 \__draw_path_curveto:nnnnnn

534 { \fp_to_dim:n { #1 - #3 - #5 * \c__draw_path_ellipse_fp } }

535 { \fp_to_dim:n { #2 - #4 - #6 * \c__draw_path_ellipse_fp } }

536 { \fp_to_dim:n { #1 - #3 * \c__draw_path_ellipse_fp - #5 } }

537 { \fp_to_dim:n { #2 - #4 * \c__draw_path_ellipse_fp - #6 } }

538 { \fp_to_dim:n { #1 - #5 } }

(15)

539 { \fp_to_dim:n { #2 - #6 } }

540 }

541 \cs_new:Npn \__draw_path_ellipse_arciv:nnnnnn #1#2#3#4#5#6

542 {

543 \__draw_path_curveto:nnnnnn

544 { \fp_to_dim:n { #1 + #3 * \c__draw_path_ellipse_fp - #5 } }

545 { \fp_to_dim:n { #2 + #4 * \c__draw_path_ellipse_fp - #6 } }

546 { \fp_to_dim:n { #1 + #3 - #5 * \c__draw_path_ellipse_fp } }

547 { \fp_to_dim:n { #2 + #4 - #6 * \c__draw_path_ellipse_fp } }

548 { \fp_to_dim:n { #1 + #3 } }

549 { \fp_to_dim:n { #2 + #4 } }

550 }

551 \fp_const:Nn \c__draw_path_ellipse_fp { \fp_use:c { c__draw_path_arc_90_fp } } (End definition for\draw_path_ellipse:nnn and others. This function is documented on page??.)

\draw_path_circle:nn A shortcut.

552 \cs_new_protected:Npn \draw_path_circle:nn #1#2

553 { \draw_path_ellipse:nnn {#1} { #2 , 0pt } { 0pt , #2 } } (End definition for\draw_path_circle:nn. This function is documented on page??.)

4.6 Rectangles

\draw_path_rectangle:nn

\__draw_path_rectangle:nnnn

\__draw_path_rectangle_rounded:nnnn

Building a rectangle can be a single operation, or for rounded versions will involve step- by-step construction.

554 \cs_new_protected:Npn \draw_path_rectangle:nn #1#2

555 {

556 \__draw_point_process:nnn

557 {

558 \bool_lazy_or:nnTF

559 { \l__draw_corner_arc_bool }

560 { \l__draw_matrix_active_bool }

561 { \__draw_path_rectangle_rounded:nnnn }

562 { \__draw_path_rectangle:nnnn }

563 }

564 { \draw_point_transform:n {#1} }

565 {#2}

566 }

567 \cs_new_protected:Npn \__draw_path_rectangle:nnnn #1#2#3#4

568 {

569 \__draw_path_update_limits:nn {#1} {#2}

570 \__draw_path_update_limits:nn { #1 + #3 } { #2 + #4 }

571 \__draw_softpath_rectangle:nnnn {#1} {#2} {#3} {#4}

572 \__draw_path_update_last:nn {#1} {#2}

573 }

574 \cs_new_protected:Npn \__draw_path_rectangle_rounded:nnnn #1#2#3#4

575 {

576 \draw_path_moveto:n { #1 + #3 , #2 + #4 }

577 \draw_path_lineto:n { #1 , #2 + #4 }

578 \draw_path_lineto:n { #1 , #2 }

579 \draw_path_lineto:n { #1 + #3 , #2 }

580 \draw_path_close:

581 \draw_path_moveto:n { #1 , #2 }

582 }

(16)

(End definition for \draw_path_rectangle:nn, \__draw_path_rectangle:nnnn, and \__draw_path_- rectangle_rounded:nnnn. This function is documented on page??.)

\draw_path_rectangle_corners:nn

\__draw_path_rectangle_corners:nnnn

Another shortcut wrapper.

583 \cs_new_protected:Npn \draw_path_rectangle_corners:nn #1#2

584 {

585 \__draw_point_process:nnn

586 { \__draw_path_rectangle_corners:nnnnn {#1} }

587 {#1} {#2}

588 }

589 \cs_new_protected:Npn \__draw_path_rectangle_corners:nnnnn #1#2#3#4#5

590 { \draw_path_rectangle:nn {#1} { #4 - #2 , #5 - #3 } }

(End definition for \draw_path_rectangle_corners:nn and \__draw_path_rectangle_corners:nnnn.

This function is documented on page??.)

4.7 Grids

\draw_path_grid:nnnn

\__draw_path_grid_auxi:nnnnnn

\__draw_path_grid_auxi:ffnnnn

\__draw_path_grid_auxii:nnnnnn

\__draw_path_grid_auxiii:nnnnnn

\__draw_path_grid_auxiiii:ffnnnn

\__draw_path_grid_auxiv:nnnnnnnn

\__draw_path_grid_auxiv:ffnnnnnn

The main complexity here is lining up the grid correctly. To keep it simple, we tidy up the argument ordering first.

591 \cs_new_protected:Npn \draw_path_grid:nnnn #1#2#3#4

592 {

593 \__draw_point_process:nnn

594 {

595 \__draw_path_grid_auxi:ffnnnn

596 { \dim_eval:n { \dim_abs:n {#1} } }

597 { \dim_eval:n { \dim_abs:n {#2} } }

598 }

599 {#3} {#4}

600 }

601 \cs_new_protected:Npn \__draw_path_grid_auxi:nnnnnn #1#2#3#4#5#6

602 {

603 \dim_compare:nNnTF {#3} > {#5}

604 { \__draw_path_grid_auxii:nnnnnn {#1} {#2} {#5} {#4} {#3} {#6} }

605 { \__draw_path_grid_auxii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} }

606 }

607 \cs_generate_variant:Nn \__draw_path_grid_auxi:nnnnnn { ff }

608 \cs_new_protected:Npn \__draw_path_grid_auxii:nnnnnn #1#2#3#4#5#6

609 {

610 \dim_compare:nNnTF {#4} > {#6}

611 { \__draw_path_grid_auxiii:nnnnnn {#1} {#2} {#3} {#6} {#5} {#4} }

612 { \__draw_path_grid_auxiii:nnnnnn {#1} {#2} {#3} {#4} {#5} {#6} }

613 }

614 \cs_new_protected:Npn \__draw_path_grid_auxiii:nnnnnn #1#2#3#4#5#6

615 {

616 \__draw_path_grid_auxiv:ffnnnnnn

617 { \fp_to_dim:n { #1 * trunc(#3/(#1)) } }

618 { \fp_to_dim:n { #2 * trunc(#4/(#2)) } }

619 {#1} {#2} {#3} {#4} {#5} {#6}

620 }

621 \cs_new_protected:Npn \__draw_path_grid_auxiv:nnnnnnnn #1#2#3#4#5#6#7#8

622 {

623 \dim_step_inline:nnnn

624 {#1}

(17)

625 {#3}

626 {#7}

627 {

628 \draw_path_moveto:n { ##1 , #6 }

629 \draw_path_lineto:n { ##1 , #8 }

630 }

631 \dim_step_inline:nnnn

632 {#2}

633 {#4}

634 {#8}

635 {

636 \draw_path_moveto:n { #5 , ##1 }

637 \draw_path_lineto:n { #7 , ##1 }

638 }

639 }

640 \cs_generate_variant:Nn \__draw_path_grid_auxiv:nnnnnnnn { ff }

(End definition for\draw_path_grid:nnnn and others. This function is documented on page??.)

4.8 Using paths

\l__draw_path_use_clip_bool

\l__draw_path_use_fill_bool

\l__draw_path_use_stroke_bool

Actions to pass to the driver.

641 \bool_new:N \l__draw_path_use_clip_bool

642 \bool_new:N \l__draw_path_use_fill_bool

643 \bool_new:N \l__draw_path_use_stroke_bool

(End definition for \l__draw_path_use_clip_bool, \l__draw_path_use_fill_bool, and \l__draw_- path_use_stroke_bool.)

\l__draw_path_use_bb_bool

\l__draw_path_use_clear_bool

Actions handled at the macro layer.

644 \bool_new:N \l__draw_path_use_bb_bool

645 \bool_new:N \l__draw_path_use_clear_bool

(End definition for\l__draw_path_use_bb_bool and\l__draw_path_use_clear_bool.)

\draw_path_use:n

\draw_path_use_clear:n

\__draw_path_use:n

\__draw_path_use_action_draw:

\__draw_path_use_action_fillstroke:

\__draw_path_use_stroke_bb:

\__draw_path_use_stroke_bb_aux:NnN

There are a range of actions which can apply to a path: they are handled in a single function which can carry out several of them. The first step is to deal with the special case of clearing the path.

646 \cs_new_protected:Npn \draw_path_use:n #1

647 {

648 \tl_if_blank:nF {#1}

649 { \__draw_path_use:n {#1} }

650 }

651 \cs_new_protected:Npn \draw_path_use_clear:n #1

652 {

653 \bool_lazy_or:nnTF

654 { \tl_if_blank_p:n {#1} }

655 { \str_if_eq_p:nn {#1} { clear } }

656 {

657 \__draw_softpath_clear:

658 \__draw_path_reset_limits:

659 }

660 { \__draw_path_use:n { #1 , clear } }

661 }

(18)

Map over the actions and set up the data: mainly just booleans, but with the possibility to cover more complex cases. The business end of the function is a series of checks on the various flags, then taking the appropriate action(s).

662 \cs_new_protected:Npn \__draw_path_use:n #1

663 {

664 \bool_set_false:N \l__draw_path_use_clip_bool

665 \bool_set_false:N \l__draw_path_use_fill_bool

666 \bool_set_false:N \l__draw_path_use_stroke_bool

667 \clist_map_inline:nn {#1}

668 {

669 \cs_if_exist:cTF { l__draw_path_use_ ##1 _ bool }

670 { \bool_set_true:c { l__draw_path_use_ ##1 _ bool } }

671 {

672 \cs_if_exist_use:cF { __draw_path_use_action_ ##1 : }

673 { \msg_error:nnn { draw } { invalid-path-action } {##1} }

674 }

675 }

676 \__draw_softpath_round_corners:

677 \bool_lazy_and:nnT

678 { \l_draw_bb_update_bool }

679 { \l__draw_path_use_stroke_bool }

680 { \__draw_path_use_stroke_bb: }

681 \__draw_softpath_use:

682 \bool_if:NT \l__draw_path_use_clip_bool

683 {

684 \__draw_backend_clip:

685 \bool_set_false:N \l_draw_bb_update_bool

686 \bool_lazy_or:nnF

687 { \l__draw_path_use_fill_bool }

688 { \l__draw_path_use_stroke_bool }

689 { \__draw_backend_discardpath: }

690 }

691 \bool_lazy_or:nnT

692 { \l__draw_path_use_fill_bool }

693 { \l__draw_path_use_stroke_bool }

694 {

695 \use:c

696 {

697 __draw_backend_

698 \bool_if:NT \l__draw_path_use_fill_bool { fill }

699 \bool_if:NT \l__draw_path_use_stroke_bool { stroke }

700 :

701 }

702 }

703 \bool_if:NT \l__draw_path_use_clear_bool

704 { \__draw_softpath_clear: }

705 }

706 \cs_new_protected:Npn \__draw_path_use_action_draw:

707 {

708 \bool_set_true:N \l__draw_path_use_stroke_bool

709 }

710 \cs_new_protected:Npn \__draw_path_use_action_fillstroke:

711 {

712 \bool_set_true:N \l__draw_path_use_fill_bool

(19)

713 \bool_set_true:N \l__draw_path_use_stroke_bool

714 }

Where the path is relevant to size and is stroked, we need to allow for the part which overlaps the edge of the bounding box.

715 \cs_new_protected:Npn \__draw_path_use_stroke_bb:

716 {

717 \__draw_path_use_stroke_bb_aux:NnN x { max } +

718 \__draw_path_use_stroke_bb_aux:NnN y { max } +

719 \__draw_path_use_stroke_bb_aux:NnN x { min } -

720 \__draw_path_use_stroke_bb_aux:NnN y { min } -

721 }

722 \cs_new_protected:Npn \__draw_path_use_stroke_bb_aux:NnN #1#2#3

723 {

724 \dim_compare:nNnF { \dim_use:c { g__draw_ #1#2 _dim } } = { #3 -\c_max_dim }

725 {

726 \dim_gset:cn { g__draw_ #1#2 _dim }

727 {

728 \use:c { dim_ #2 :nn }

729 { \dim_use:c { g__draw_ #1#2 _dim } }

730 {

731 \dim_use:c { g__draw_path_ #1#2 _dim }

732 #3 0.5 \g__draw_linewidth_dim

733 }

734 }

735 }

736 }

(End definition for\draw_path_use:n and others. These functions are documented on page??.)

4.9 Scoping paths

\l__draw_path_lastx_dim

\l__draw_path_lasty_dim

\l__draw_path_xmax_dim

\l__draw_path_xmin_dim

\l__draw_path_ymax_dim

\l__draw_path_ymin_dim

\l__draw_softpath_corners_bool

Local storage for global data. There is already a\l__draw_softpath_main_tlfor path manipulation, so we can reuse that (it is always grouped when the path is being recon- structed).

737 \dim_new:N \l__draw_path_lastx_dim

738 \dim_new:N \l__draw_path_lasty_dim

739 \dim_new:N \l__draw_path_xmax_dim

740 \dim_new:N \l__draw_path_xmin_dim

741 \dim_new:N \l__draw_path_ymax_dim

742 \dim_new:N \l__draw_path_ymin_dim

743 \dim_new:N \l__draw_softpath_lastx_dim

744 \dim_new:N \l__draw_softpath_lasty_dim

745 \bool_new:N \l__draw_softpath_corners_bool (End definition for\l__draw_path_lastx_dim and others.)

\draw_path_scope_begin:

\draw_path_scope_end:

Scoping a path is a bit more involved, largely as there are a number of variables to keep hold of.

746 \cs_new_protected:Npn \draw_path_scope_begin:

747 {

748 \group_begin:

749 \dim_set_eq:NN \l__draw_path_lastx_dim \g__draw_path_lastx_dim

750 \dim_set_eq:NN \l__draw_path_lasty_dim \g__draw_path_lasty_dim

(20)

751 \dim_set_eq:NN \l__draw_path_xmax_dim \g__draw_path_xmax_dim

752 \dim_set_eq:NN \l__draw_path_xmin_dim \g__draw_path_xmin_dim

753 \dim_set_eq:NN \l__draw_path_ymax_dim \g__draw_path_ymax_dim

754 \dim_set_eq:NN \l__draw_path_ymin_dim \g__draw_path_ymin_dim

755 \dim_set_eq:NN \l__draw_softpath_lastx_dim \g__draw_softpath_lastx_dim

756 \dim_set_eq:NN \l__draw_softpath_lasty_dim \g__draw_softpath_lasty_dim

757 \__draw_path_reset_limits:

758 \tl_build_get:NN \g__draw_softpath_main_tl \l__draw_softpath_main_tl

759 \bool_set_eq:NN

760 \l__draw_softpath_corners_bool

761 \g__draw_softpath_corners_bool

762 \__draw_softpath_clear:

763 }

764 \cs_new_protected:Npn \draw_path_scope_end:

765 {

766 \__draw_softpath_clear:

767 \bool_gset_eq:NN

768 \g__draw_softpath_corners_bool

769 \l__draw_softpath_corners_bool

770 \__draw_softpath_add:o \l__draw_softpath_main_tl

771 \dim_gset_eq:NN \g__draw_softpath_lastx_dim \l__draw_softpath_lastx_dim

772 \dim_gset_eq:NN \g__draw_softpath_lasty_dim \l__draw_softpath_lasty_dim

773 \dim_gset_eq:NN \g__draw_path_xmax_dim \l__draw_path_xmax_dim

774 \dim_gset_eq:NN \g__draw_path_xmin_dim \l__draw_path_xmin_dim

775 \dim_gset_eq:NN \g__draw_path_ymax_dim \l__draw_path_ymax_dim

776 \dim_gset_eq:NN \g__draw_path_ymin_dim \l__draw_path_ymin_dim

777 \dim_gset_eq:NN \g__draw_path_lastx_dim \l__draw_path_lastx_dim

778 \dim_gset_eq:NN \g__draw_path_lasty_dim \l__draw_path_lasty_dim

779 \group_end:

780 }

(End definition for\draw_path_scope_begin: and\draw_path_scope_end:. These functions are docu- mented on page??.)

781 \msg_new:nnnn { draw } { invalid-path-action }

782 { Invalid~action~’#1’~for~path. }

783 { Paths~can~be~used~with~actions~’draw’,~’clip’,~’fill’~or~’stroke’. }

784 % \end{macrocode}

785 %

786 % \begin{macrocode}

787 ⟨/package⟩

5 l3draw-points implementation

788 ⟨∗package⟩

789 ⟨@@=draw⟩

This sub-module covers more-or-less the same ideas as pgfcorepoints.code.tex, though the approach taken to returning values is different: point expressions here are processed by expansion and return a co-ordinate pair in the form{⟨x⟩}{⟨y⟩}. Equivalents of followingpgf functions are deliberately omitted:

• \pgfpointorigin: Can be given explicitly as0pt,0pt.

• \pgfpointadd,\pgfpointdiff,\pgfpointscale: Can be given explicitly.

(21)

• \pgfextractx, \pgfextracty: Available by applying \use_i:nn/\use_ii:nn or similar to the x-type expansion of a point expression.

• \pgfgetlastxy: Unused in the entire pgfcore, may be emulated byx-type expan- sion of a point expression, then using the result.

In addition, equivalents of the followingmaybe added in future but are currently absent:

• \pgfpointcylindrical,\pgfpointspherical: The usefulness of these commands is not currently clear.

• \pgfpointborderrectangle,\pgfpointborderellipse: To be revisited once the semantics and use cases are clear.

• \pgfqpoint,\pgfqpointscale,\pgfqpointpolar,\pgfqpointxy,\pgfqpointxyz:

The expandable approach taken in the code here, along with the absolute require- ment for ε-TEX, means it is likely many use cases for these commands may be covered in other ways. This may be revisited as higher-level structures are con- structed.

5.1 Support functions

\__draw_point_process:nn

\__draw_point_process_auxi:nn

\__draw_point_process_auxii:nw

\__draw_point_process:nnn

\__draw_point_process_auxiii:nnn

\__draw_point_process_auxiv:nw

\__draw_point_process:nnnn

\__draw_point_process_auxv:nnnn

\__draw_point_process_auxvi:nw

\__draw_point_process:nnnnn

\__draw_point_process_auxvii:nnnnn

\__draw_point_process_auxviii:nw

Execute whatever code is passed to extract thexandyco-ordinates. The first argument here should itself absorb two arguments. There is also a version to deal with two co- ordinates: common enough to justify a separate function.

790 \cs_new:Npn \__draw_point_process:nn #1#2

791 {

792 \exp_args:Nf \__draw_point_process_auxi:nn

793 { \draw_point:n {#2} }

794 {#1}

795 }

796 \cs_new:Npn \__draw_point_process_auxi:nn #1#2

797 { \__draw_point_process_auxii:nw {#2} #1 \s__draw_stop }

798 \cs_new:Npn \__draw_point_process_auxii:nw #1 #2 , #3 \s__draw_stop

799 { #1 {#2} {#3} }

800 \cs_new:Npn \__draw_point_process:nnn #1#2#3

801 {

802 \exp_args:Nff \__draw_point_process_auxiii:nnn

803 { \draw_point:n {#2} }

804 { \draw_point:n {#3} }

805 {#1}

806 }

807 \cs_new:Npn \__draw_point_process_auxiii:nnn #1#2#3

808 { \__draw_point_process_auxiv:nw {#3} #1 \s__draw_mark #2 \s__draw_stop }

809 \cs_new:Npn \__draw_point_process_auxiv:nw #1 #2 , #3 \s__draw_mark #4 , #5 \s__draw_stop

810 { #1 {#2} {#3} {#4} {#5} }

811 \cs_new:Npn \__draw_point_process:nnnn #1#2#3#4

812 {

813 \exp_args:Nfff \__draw_point_process_auxv:nnnn

814 { \draw_point:n {#2} }

815 { \draw_point:n {#3} }

816 { \draw_point:n {#4} }

817 {#1}

818 }

(22)

819 \cs_new:Npn \__draw_point_process_auxv:nnnn #1#2#3#4

820 { \__draw_point_process_auxvi:nw {#4} #1 \s__draw_mark #2 \s__draw_mark #3 \s__draw_stop }

821 \cs_new:Npn \__draw_point_process_auxvi:nw

822 #1 #2 , #3 \s__draw_mark #4 , #5 \s__draw_mark #6 , #7 \s__draw_stop

823 { #1 {#2} {#3} {#4} {#5} {#6} {#7} }

824 \cs_new:Npn \__draw_point_process:nnnnn #1#2#3#4#5

825 {

826 \exp_args:Nffff \__draw_point_process_auxvii:nnnnn

827 { \draw_point:n {#2} }

828 { \draw_point:n {#3} }

829 { \draw_point:n {#4} }

830 { \draw_point:n {#5} }

831 {#1}

832 }

833 \cs_new:Npn \__draw_point_process_auxvii:nnnnn #1#2#3#4#5

834 {

835 \__draw_point_process_auxviii:nw

836 {#5} #1 \s__draw_mark #2 \s__draw_mark #3 \s__draw_mark #4 \s__draw_stop

837 }

838 \cs_new:Npn \__draw_point_process_auxviii:nw

839 #1 #2 , #3 \s__draw_mark #4 , #5 \s__draw_mark #6 , #7 \s__draw_mark #8 , #9 \s__draw_stop

840 { #1 {#2} {#3} {#4} {#5} {#6} {#7} {#8} {#9} } (End definition for\__draw_point_process:nn and others.)

5.2 Basic points

\draw_point:n

\__draw_point_to_dim:n

\__draw_point_to_dim:f

\__draw_point_to_dim:w

Co-ordinates are always returned as two dimensions.

841 \cs_new:Npn \draw_point:n #1

842 { \__draw_point_to_dim:f { \fp_eval:n {#1} } }

843 \cs_new:Npn \__draw_point_to_dim:n #1

844 { \__draw_point_to_dim:w #1 }

845 \cs_generate_variant:Nn \__draw_point_to_dim:n { f }

846 \cs_new:Npn \__draw_point_to_dim:w ( #1 , ~ #2 ) { #1pt , #2pt }

5.3 Polar co-ordinates

\draw_point_polar:nn

\draw_point_polar:nnn

\__draw_draw_polar:nnn

\__draw_draw_polar:fnn

Polar co-ordinates may have either one or two lengths, so there is a need to do a sim- ple split before the calculation. As the angle gets used twice, save on any expression evaluation there and force expansion.

847 \cs_new:Npn \draw_point_polar:nn #1#2

848 { \draw_point_polar:nnn {#1} {#1} {#2} }

849 \cs_new:Npn \draw_point_polar:nnn #1#2#3

850 { \__draw_draw_polar:fnn { \fp_eval:n {#3} } {#1} {#2} }

851 \cs_new:Npn \__draw_draw_polar:nnn #1#2#3

852 { \draw_point:n { cosd(#1) * (#2) , sind(#1) * (#3) } }

853 \cs_generate_variant:Nn \__draw_draw_polar:nnn { f }

5.4 Point expression arithmetic

These functions all take point expressions as arguments.

(23)

\draw_point_unit_vector:n

\__draw_point_unit_vector:nn

\__draw_point_unit_vector:nnn

The outcome is the normalised vector from (0,0) in the direction of the point,i.e.

Px= x

px2+y2 Py= y px2+y2

except where the length is zero, in which case a vertical vector is returned.

854 \cs_new:Npn \draw_point_unit_vector:n #1

855 { \__draw_point_process:nn { \__draw_point_unit_vector:nn } {#1} }

856 \cs_new:Npn \__draw_point_unit_vector:nn #1#2

857 {

858 \exp_args:Nf \__draw_point_unit_vector:nnn

859 { \fp_eval:n { (sqrt(#1 * #1 + #2 * #2)) } }

860 {#1} {#2}

861 }

862 \cs_new:Npn \__draw_point_unit_vector:nnn #1#2#3

863 {

864 \fp_compare:nNnTF {#1} = \c_zero_fp

865 { 0pt, 1pt }

866 {

867 \draw_point:n

868 { ( #2 , #3 ) / #1 }

869 }

870 }

5.5 Intersection calculations

\draw_point_intersect_lines:nnnn

\__draw_point_intersect_lines:nnnnnn

\__draw_point_intersect_lines:nnnnnnnn

\__draw_point_intersect_lines_aux:nnnnnn

\__draw_point_intersect_lines_aux:ffffff

The intersection pointP between a line joining points (x1, y1) and (x2, y2) with a second line joining points (x3, y3) and (x4, y4) can be calculated using the formulae

Px=(x1y2y1x2)(x3x4)−(x3y4y3x4)(x1x2) (x1x2)(y3y4)−(y1y2)(x3x4) and

Py= (x1y2y1x2)(y3y5)−(x3y4y3x4)(y1y2) (x1x2)(y3y4)−(y1y2)(x3x4)

The work therefore comes down to expanding the incoming data, then pre-calculating as many parts as possible before the final work to find the intersection. (Expansion and argument re-ordering is much less work than additional floating point calculations.)

871 \cs_new:Npn \draw_point_intersect_lines:nnnn #1#2#3#4

872 {

873 \__draw_point_process:nnnnn

874 { \__draw_point_intersect_lines:nnnnnnnn }

875 {#1} {#2} {#3} {#4}

876 }

At this stage we have all of the information we need, fully expanded:

#1 x1

#2 y1

#3 x2

#4 y2

(24)

#5 x3

#6 y3

#7 x4

#8 y4

so now just have to do all of the calculation.

877 \cs_new:Npn \__draw_point_intersect_lines:nnnnnnnn #1#2#3#4#5#6#7#8

878 {

879 \__draw_point_intersect_lines_aux:ffffff

880 { \fp_eval:n { #1 * #4 - #2 * #3 } }

881 { \fp_eval:n { #5 * #8 - #6 * #7 } }

882 { \fp_eval:n { #1 - #3 } }

883 { \fp_eval:n { #5 - #7 } }

884 { \fp_eval:n { #2 - #4 } }

885 { \fp_eval:n { #6 - #8 } }

886 }

887 \cs_new:Npn \__draw_point_intersect_lines_aux:nnnnnn #1#2#3#4#5#6

888 {

889 \draw_point:n

890 {

891 ( #2 * #3 - #1 * #4 , #2 * #5 - #1 * #6 )

892 / ( #4 * #5 - #6 * #3 )

893 }

894 }

895 \cs_generate_variant:Nn \__draw_point_intersect_lines_aux:nnnnnn { ffffff }

\draw_point_intersect_circles:nnnnn

\__draw_point_intersect_circles_auxi:nnnnnnn

\__draw_point_intersect_circles_auxii:nnnnnnn

\__draw_point_intersect_circles_auxii:ffnnnnn

\__draw_point_intersect_circles_auxiii:nnnnnnn

\__draw_point_intersect_circles_auxiii:ffnnnnn

\__draw_point_intersect_circles_auxiv:nnnnnnnn

\__draw_point_intersect_circles_auxiv:fnnnnnnn

\__draw_point_intersect_circles_auxv:nnnnnnnnn

\__draw_point_intersect_circles_auxv:ffnnnnnnn

\__draw_point_intersect_circles_auxvi:nnnnnnnn

\__draw_point_intersect_circles_auxvi:fnnnnnnn

\__draw_point_intersect_circles_auxvii:nnnnnnn

\__draw_point_intersect_circles_auxvii:fffnnnn

Another long expansion chain to get the values in the right places. We have two circles, the first with center (a, b) and radius r, the second with center (c, d) and radiuss. We use the intermediate values

e=ca f =db

p=p e2+f2 k= p2+r2s2

2p in either

Px=a+ek p +f

p

pr2k2

Py =b+f k pe

p

pr2k2 or

Px=a+ek pf

p

pr2k2

Py =b+f k p +e

p

pr2k2

References

Related documents

The investigation of portfolio optimisation performance is undertaken using an alternative portfolio constructed as follows: (1) the benchmark portfolio is established as at 1 May

(Kawakami, 2009, p. 22) because they were language learners. This paper holds that social identity is closely connected to a sense of belonging and sense of self. The case

The Paulsgrove and Bellanbi properties (excepting a fen snail parcels already sold or contracted to bo sold) and two 3nallcr parcels in Illawarra were conveyed to John

Although the teachers in this research collectively made progress in their understanding of the meaning of dividing fractions through exploration of an area

The hitting probability describes the probability that the Markov chain will ever reach some state or set of states.. In this section we show how hitting probabilities can be written

Also, note that the enumeration of (B, q) is never delayed, and when some requirement in the diagonalization phase is delaying the definition of B e , all other structures B k for k

This is an academic requirement that is formally done, and once the student finishes the written work and is checked by the supervisor (mentor), the project should be approved by

If the prime dividing a solution n is congruent to 3 modulo 8 then it must be greater than 41, and every solution is divisible by at least the fourth power of an odd prime. Moreover

Because everything else was equal in all five sections, any changes in students’ total assessment scores in the experimental classes compared to the total assessments scores of

asymmetrical patterns, but symmetry comes more naturally to them (Giurfa et al, 1996).  Bees are not reflective animals, and it is hard to believe they deal in “relations of

The quantum technique is to “embed” the classical computing box (given by f ) into a quantum box, then use the quantum device on a “superposition” state, and finally make a

An important difference between elliptic and hyperelliptic curves is that there exist algorithms to solve the discrete logarithm problem in the Jacobian of a hyperelliptic curve

Our strategy is to prove that connected matroids make up at least half of the set of loopless and coloop- less labeled matroids on n elements.. To show that this implies Theorem 1.1,

"No less Nay, bigger women grow by men" Her attitude clearly is that a wife's pregnancy is a natural matter for rejoicing. But it is a wife's pregnancy: she clearly regards

Show that if an elliptic curve E can be written in twisted Edwards model then the only non-trivial twist of E that can also be written in twisted Edwards model is the quadratic

program. An atomic operation that can be done or undone is represented by an Operation, which 

For the remainder of this section we formally define the graph families k –Vertex Cover , where k is an upper bound on the vertex cover size, and what it means to characterize them by

Limit curve is the quadratic B-spline defined by the original control polygon. COMPSCI 715 Curves

Since in long-run equilibrium each city must offer the same ex- pected real income, pay and unemployment will be posi- tively correlated in a cross-section of cities (and

Once the total head against which the pump must operate has been determined, the calculation of water power is the next step in the process of arriving at the motor power

First, we study curves in a Euclidean space of arbitrary dimension such that the chord joining any two points on the curve meets it at the same angle.. Next, we study hypersurfaces in

As we outlined at the outset, this means we need to consider what is meant by regulation risk, what do we mean when we talk about regulatory changes, and how can anticipating

Each transect is set up in the riparian zone, perpendicular (i.e. at a 90° angle) to the direction of the stream bank, and is used to carry out measurements for vegetation width,