├── .editorconfig
├── .github
├── FUNDING.yml
└── workflows
│ └── ci.yml
├── .gitignore
├── .gitmodules
├── CHANGES.md
├── LICENSE
├── README.md
├── cetz-core
├── Cargo.lock
├── Cargo.toml
└── src
│ └── lib.rs
├── docs
├── advanced
│ ├── advanced.md
│ ├── context.mdx
│ ├── custom-types.mdx
│ ├── draw-functions.mdx
│ └── transformations.mdx
├── api
│ ├── draw-functions
│ │ ├── draw-functions.md
│ │ ├── grouping
│ │ │ ├── anchor.mdx
│ │ │ ├── copy-anchors.mdx
│ │ │ ├── floating.mdx
│ │ │ ├── for-each-anchor.mdx
│ │ │ ├── get-ctx.mdx
│ │ │ ├── group.mdx
│ │ │ ├── grouping.md
│ │ │ ├── hide.mdx
│ │ │ ├── intersections.mdx
│ │ │ ├── on-layer.mdx
│ │ │ ├── scope.mdx
│ │ │ └── set-ctx.mdx
│ │ ├── projections
│ │ │ ├── on-xy.mdx
│ │ │ ├── on-xz.mdx
│ │ │ ├── on-yz.mdx
│ │ │ ├── ortho.mdx
│ │ │ └── projections.md
│ │ ├── shapes
│ │ │ ├── arc.mdx
│ │ │ ├── bezier.mdx
│ │ │ ├── catmull.mdx
│ │ │ ├── circle.mdx
│ │ │ ├── content.mdx
│ │ │ ├── grid.mdx
│ │ │ ├── hobby.mdx
│ │ │ ├── line.mdx
│ │ │ ├── mark.mdx
│ │ │ ├── merge-path.mdx
│ │ │ ├── polygon.mdx
│ │ │ ├── rect.mdx
│ │ │ └── shapes.md
│ │ ├── styling
│ │ │ ├── fill.mdx
│ │ │ ├── set-style.mdx
│ │ │ ├── stroke.mdx
│ │ │ └── styling.md
│ │ └── transformations
│ │ │ ├── move-to.mdx
│ │ │ ├── rotate.mdx
│ │ │ ├── scale.mdx
│ │ │ ├── set-origin.mdx
│ │ │ ├── set-transform.mdx
│ │ │ ├── set-viewport.mdx
│ │ │ ├── transformations.md
│ │ │ └── translate.mdx
│ ├── internal
│ │ ├── aabb.mdx
│ │ ├── anchor.mdx
│ │ ├── bezier.mdx
│ │ ├── canvas.mdx
│ │ ├── complex.mdx
│ │ ├── coordinate.mdx
│ │ ├── drawable.mdx
│ │ ├── hobby.mdx
│ │ ├── internal.md
│ │ ├── intersection.mdx
│ │ ├── mark.mdx
│ │ ├── matrix.mdx
│ │ ├── path-util.mdx
│ │ ├── process.mdx
│ │ ├── styles.mdx
│ │ ├── util.mdx
│ │ └── vector.mdx
│ ├── libraries
│ │ ├── angle
│ │ │ ├── angle.mdx
│ │ │ ├── index.md
│ │ │ └── right-angle.mdx
│ │ ├── decorations
│ │ │ ├── braces
│ │ │ │ ├── brace.mdx
│ │ │ │ ├── flat-brace.mdx
│ │ │ │ └── index.md
│ │ │ ├── index.md
│ │ │ └── path
│ │ │ │ ├── coil.mdx
│ │ │ │ ├── index.mdx
│ │ │ │ ├── wave.mdx
│ │ │ │ └── zigzag.mdx
│ │ ├── index.md
│ │ ├── palette
│ │ │ ├── index.mdx
│ │ │ └── new.mdx
│ │ └── tree
│ │ │ ├── index.md
│ │ │ └── tree.mdx
│ ├── overview.md
│ └── sidebar.js
├── basics
│ ├── anchors.mdx
│ ├── basics.md
│ ├── canvas.md
│ ├── coordinate-systems.mdx
│ ├── custom-types.mdx
│ ├── marks.mdx
│ └── styling.mdx
├── custom-types.js
├── getting-started.mdx
├── internals
│ └── internals.md
├── libraries
│ ├── libraries.md
│ ├── plot.mdx
│ └── tree.mdx
├── overview.md
├── sidebar.js
└── tutorials
│ └── karl.mdx
├── gallery
├── karls-picture.png
├── karls-picture.typ
├── paciolis.png
├── paciolis.typ
├── periodic-table.png
├── periodic-table.typ
├── plate-capacitor.png
├── plate-capacitor.typ
├── tree.png
├── tree.typ
├── waves.png
└── waves.typ
├── justfile
├── requirements.typ
├── src
├── aabb.typ
├── anchor.typ
├── bezier.typ
├── canvas.typ
├── complex.typ
├── coordinate.typ
├── deps.typ
├── draw.typ
├── draw
│ ├── grouping.typ
│ ├── projection.typ
│ ├── shapes.typ
│ ├── styling.typ
│ ├── transformations.typ
│ └── util.typ
├── drawable.typ
├── hobby.typ
├── intersection.typ
├── lib.typ
├── lib
│ ├── angle.typ
│ ├── decorations.typ
│ ├── decorations
│ │ ├── brace.typ
│ │ └── path.typ
│ ├── palette.typ
│ └── tree.typ
├── mark-shapes.typ
├── mark.typ
├── matrix.typ
├── path-util.typ
├── polygon.typ
├── process.typ
├── sorting.typ
├── styles.typ
├── util.typ
├── vector.typ
└── version.typ
├── tests
├── .gitignore
├── anchor-centroid
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── angle
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── arc-previous-position
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── arc-through
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── arc
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── arrows
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── bezier-shortening
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── bezier-through
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── bezier
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── bounds
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── canvas-baseline
│ └── test.typ
├── catmul
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── circle-through
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── circle
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-anchors
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-intersection
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-padding
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-rotation
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-rtl
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-span
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content-transform
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── content
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── coordinate-lerp
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── coordinate
│ └── custom
│ │ ├── ref
│ │ └── 1.png
│ │ └── test.typ
├── copy-anchor
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── cube
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── custom-mark
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── decorations
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── element-anchors
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── empty-group
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── empty
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── floating
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── gradient
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── grid
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── group-anchors
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── group-nested-anchors
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── group-none
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── group-padding
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── group-transform
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── group-translate
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── helper.typ
├── hide
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── hobby
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── image
│ ├── image.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── intersection
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── layer
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── line-element-element-intersection
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── line-fill-rule
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── local-anchor
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── mark-anchors
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── mark-auto-offset
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── mark-position
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── mark-shape-transform
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── mark-single
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── mark-z-axis
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── matrix
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── merge
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── multiple-marks
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── padding
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── palette
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── path-anchors
│ ├── ref.png
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── path-decoration
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── polygon
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── primitives
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── projection-default
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── projection-ortho
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── rect-rounded
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── rect
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── relative-length
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── relative-no-update
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── right-angle
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── ring
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── root-anchor
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── rotate-around
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── rotation
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── set-get-ctx
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── style
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── transform-precission
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── translation
│ ├── ref
│ │ └── 1.png
│ └── test.typ
├── tree
│ ├── ref
│ │ └── 1.png
│ └── test.typ
└── viewport
│ ├── ref
│ └── 1.png
│ └── test.typ
└── typst.toml
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | end_of_line = lf
5 | insert_final_newline = true
6 | indent_style = space
7 | indent_size = 2
8 |
9 | [Makefile]
10 | indent_style = tab
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [johannes-wolf,fenjalien]
2 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: Test
2 | on:
3 | push:
4 | branches:
5 | - main
6 | - master
7 | pull_request:
8 | branches:
9 | - '**'
10 |
11 | jobs:
12 | ci:
13 | runs-on: ubuntu-latest
14 | if: github.event.pull_request.draft == false
15 | steps:
16 | - uses: actions/checkout@v3
17 | with:
18 | submodules: recursive
19 | - name: Install wasm32 target
20 | run: rustup target add wasm32-unknown-unknown
21 | - name: Install just from crates.io
22 | uses: baptiste0928/cargo-install@v3
23 | with:
24 | crate: just
25 | - name: Install tytanic
26 | uses: baptiste0928/cargo-install@v3
27 | with:
28 | crate: tytanic
29 | git: https://github.com/tingerrr/tytanic.git
30 | - uses: typst-community/setup-typst@v3
31 | with:
32 | typst-version: '0.13.1'
33 | cache-dependency-path: src/deps.typ
34 | - run: |
35 | typst --version
36 | tt --version
37 | just install @local
38 | just install @preview
39 | just test
40 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | docs/_generated
2 | tmp*
3 | **/target/
4 | cetz-core/cetz_core.wasm
5 | **/.rustc_info.json
6 |
7 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "common"]
2 | path = common
3 | url = https://github.com/cetz-package/common.git
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CeTZ
2 |
3 | CeTZ (CeTZ, ein Typst Zeichenpaket) is a library for drawing with [Typst](https://typst.app) with an API inspired by TikZ and [Processing](https://processing.org/).
4 |
5 | ## Examples
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 | |
14 |
15 |
16 |
17 |
18 | |
19 |
20 |
21 |
22 |
23 | |
24 |
25 |
26 | Karl's Picture |
27 | Pacioli's construction of the icosahedron |
28 | Waves |
29 |
30 |
31 |
32 |
33 |
34 |
35 | |
36 |
37 |
38 |
39 |
40 | |
41 |
42 |
43 |
44 |
45 | |
46 |
47 |
48 | Tree Layout |
49 | Periodic Table of Elements |
50 | Plate Capacitor |
51 |
52 |
53 |
54 | *Click on the example image to jump to the code.*
55 |
56 | You can explore an example gallery of scientific diagrams at [janosh.github.io/diagrams](https://janosh.github.io/diagrams).
57 |
58 | ## Usage
59 |
60 | For information, see the [online manual](https://cetz-package.github.io/docs).
61 |
62 | To use this package, simply add the following code to your document:
63 |
64 | ```typ
65 | #import "@preview/cetz:0.3.4"
66 |
67 | #cetz.canvas({
68 | import cetz.draw: *
69 | // Your drawing code goes here
70 | })
71 | ```
72 |
73 | ## CeTZ Libraries
74 |
75 | - [cetz-plot - Plotting and Charts Library](https://github.com/cetz-package/cetz-plot)
76 | - [cetz-venn - Simple two- or three-set Venn diagrams](https://github.com/cetz-package/cetz-venn)
77 |
78 | ## Installing
79 |
80 | To install the CeTZ package under [your local typst package dir](https://github.com/typst/packages?tab=readme-ov-file#local-packages) you can use the `install` script from the repository.
81 |
82 | ```bash
83 | just install
84 | ```
85 |
86 | The installed version can be imported by prefixing the package name with `@local`.
87 |
88 | ```typ
89 | #import "@local/cetz:0.3.4"
90 |
91 | #cetz.canvas({
92 | import cetz.draw: *
93 | // Your drawing code goes here
94 | })
95 | ```
96 |
97 | ### Just
98 |
99 | This project uses [just](https://github.com/casey/just), a handy command runner.
100 |
101 | You can run all commands without having `just` installed, just have a look into the `justfile`.
102 | To install `just` on your system, use your systems package manager. On Windows, [Cargo](https://doc.rust-lang.org/cargo/) (`cargo install just`), [Chocolatey](https://chocolatey.org/) (`choco install just`) and [some other sources](https://just.systems/man/en/chapter_4.html) can be used. You need to run it from a `sh` compatible shell on Windows (e.g git-bash).
103 |
104 | ## Testing
105 |
106 | This package comes with some unit tests under the `tests` directory.
107 | To run all tests you can run the `just test` target. You need to have
108 | [`tytanic`](https://github.com/tingerrr/tytanic/) in your `PATH`: `cargo install tytanic`.
109 |
110 | ## Projects using CeTZ
111 | - [conchord](https://github.com/sitandr/conchord) Package for writing lyrics with chords that generates fretboard diagrams using CeTZ.
112 | - [finite](https://github.com/jneug/typst-finite) Finite is a Typst package for rendering finite automata.
113 | - [fletcher](https://github.com/Jollywatt/typst-fletcher) Package for drawing commutative diagrams and figures with arrows.
114 | - [chronos](https://git.kb28.ch/HEL/chronos) Package for drawing sequence diagrams.
115 | - [circuiteria](https://git.kb28.ch/HEL/circuiteria) Package for drawing circuits.
116 | - [rivet](https://git.kb28.ch/HEL/rivet-typst) Package for drawing instruction / register diagrams.
117 | - [plotsy-3d](https://github.com/misskacie/plotsy-3d) Package for rendering 3D objects & plots.
118 |
--------------------------------------------------------------------------------
/cetz-core/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 4
4 |
5 | [[package]]
6 | name = "cetz-core"
7 | version = "0.1.0"
8 | dependencies = [
9 | "ciborium",
10 | "serde",
11 | "wasm-minimal-protocol",
12 | ]
13 |
14 | [[package]]
15 | name = "cfg-if"
16 | version = "1.0.0"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
19 |
20 | [[package]]
21 | name = "ciborium"
22 | version = "0.2.2"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "42e69ffd6f0917f5c029256a24d0161db17cea3997d185db0d35926308770f0e"
25 | dependencies = [
26 | "ciborium-io",
27 | "ciborium-ll",
28 | "serde",
29 | ]
30 |
31 | [[package]]
32 | name = "ciborium-io"
33 | version = "0.2.2"
34 | source = "registry+https://github.com/rust-lang/crates.io-index"
35 | checksum = "05afea1e0a06c9be33d539b876f1ce3692f4afea2cb41f740e7743225ed1c757"
36 |
37 | [[package]]
38 | name = "ciborium-ll"
39 | version = "0.2.2"
40 | source = "registry+https://github.com/rust-lang/crates.io-index"
41 | checksum = "57663b653d948a338bfb3eeba9bb2fd5fcfaecb9e199e87e1eda4d9e8b240fd9"
42 | dependencies = [
43 | "ciborium-io",
44 | "half",
45 | ]
46 |
47 | [[package]]
48 | name = "crunchy"
49 | version = "0.2.3"
50 | source = "registry+https://github.com/rust-lang/crates.io-index"
51 | checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929"
52 |
53 | [[package]]
54 | name = "half"
55 | version = "2.5.0"
56 | source = "registry+https://github.com/rust-lang/crates.io-index"
57 | checksum = "7db2ff139bba50379da6aa0766b52fdcb62cb5b263009b09ed58ba604e14bbd1"
58 | dependencies = [
59 | "cfg-if",
60 | "crunchy",
61 | ]
62 |
63 | [[package]]
64 | name = "proc-macro2"
65 | version = "1.0.94"
66 | source = "registry+https://github.com/rust-lang/crates.io-index"
67 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84"
68 | dependencies = [
69 | "unicode-ident",
70 | ]
71 |
72 | [[package]]
73 | name = "quote"
74 | version = "1.0.40"
75 | source = "registry+https://github.com/rust-lang/crates.io-index"
76 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
77 | dependencies = [
78 | "proc-macro2",
79 | ]
80 |
81 | [[package]]
82 | name = "serde"
83 | version = "1.0.219"
84 | source = "registry+https://github.com/rust-lang/crates.io-index"
85 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
86 | dependencies = [
87 | "serde_derive",
88 | ]
89 |
90 | [[package]]
91 | name = "serde_derive"
92 | version = "1.0.219"
93 | source = "registry+https://github.com/rust-lang/crates.io-index"
94 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
95 | dependencies = [
96 | "proc-macro2",
97 | "quote",
98 | "syn",
99 | ]
100 |
101 | [[package]]
102 | name = "syn"
103 | version = "2.0.100"
104 | source = "registry+https://github.com/rust-lang/crates.io-index"
105 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0"
106 | dependencies = [
107 | "proc-macro2",
108 | "quote",
109 | "unicode-ident",
110 | ]
111 |
112 | [[package]]
113 | name = "unicode-ident"
114 | version = "1.0.18"
115 | source = "registry+https://github.com/rust-lang/crates.io-index"
116 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
117 |
118 | [[package]]
119 | name = "venial"
120 | version = "0.5.0"
121 | source = "registry+https://github.com/rust-lang/crates.io-index"
122 | checksum = "61584a325b16f97b5b25fcc852eb9550843a251057a5e3e5992d2376f3df4bb2"
123 | dependencies = [
124 | "proc-macro2",
125 | "quote",
126 | ]
127 |
128 | [[package]]
129 | name = "wasm-minimal-protocol"
130 | version = "0.1.0"
131 | source = "registry+https://github.com/rust-lang/crates.io-index"
132 | checksum = "264a7e0acbdd292aca03fee87eaea5a07647394c8985b19be27e950bde57930a"
133 | dependencies = [
134 | "proc-macro2",
135 | "quote",
136 | "venial",
137 | ]
138 |
--------------------------------------------------------------------------------
/cetz-core/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "cetz-core"
3 | version = "0.1.0"
4 | edition = "2021"
5 | # To avoid accidentally publishing on crates.io.
6 | publish = false
7 |
8 | [lib]
9 | crate-type = ["cdylib"]
10 |
11 | [dependencies]
12 | ciborium = "0.2.1"
13 | serde = "1.0.219"
14 | wasm-minimal-protocol = "0.1"
15 |
16 | [profile.release]
17 | lto = true
18 | strip = true
19 | opt-level = 'z'
20 | codegen-units = 1
21 | panic = "abort"
22 |
--------------------------------------------------------------------------------
/docs/advanced/advanced.md:
--------------------------------------------------------------------------------
1 | # Advanced
2 |
3 | {{int}}
4 |
--------------------------------------------------------------------------------
/docs/advanced/context.mdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/docs/advanced/context.mdx
--------------------------------------------------------------------------------
/docs/advanced/custom-types.mdx:
--------------------------------------------------------------------------------
1 | # Custom Types
2 |
3 | ## context
4 |
5 | A {{dictionary}} that holds the internal state of the canvas such as the element dictionary, the current transformation matrix, group and canvas unit length.
6 | The following fields are considered stable:
7 | - length (length): Length of one canvas unit as typst length
8 | - transform (matrix): Current 4x4 transformation matrix
9 | - background (none,color,gradient,tiling): The canvas' background
10 | - debug (bool): True if the canvas' debug flag is set
11 | - shared-state (dictionary): State that is not scoped by `group` or `scope` elements and can be used to share canvas-global state
12 |
13 | ## element
14 |
15 | A function that, when called with a context, returns some data that effects the canvas. Can also be an array of this type.
16 |
--------------------------------------------------------------------------------
/docs/advanced/draw-functions.mdx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/docs/advanced/draw-functions.mdx
--------------------------------------------------------------------------------
/docs/advanced/transformations.mdx:
--------------------------------------------------------------------------------
1 | The default transformation matrix of the canvas is set to:
2 | /// $mat(1, 0,-0.5, 0;
3 | /// 0,-1, 0.5, 0;
4 | /// 0, 0, 0, 0;
5 | /// 0, 0, 0, 1)$
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/draw-functions.md:
--------------------------------------------------------------------------------
1 | # Draw Functions
2 |
3 | Draw functions are the functions you import from the `draw` module and call within a `canvas` body. Depending on how and where you call them they can cause stuff to be drawn to the canvas or modify what is already on the canvas.
4 |
5 | - [shapes](./shapes) For drawing shapes on the canvas.
6 | - [grouping](./grouping) For grouping other draw functions together.
7 | - [styling](./styling) For changing the styling of other draw functions.
8 | - [transformations](./transformations) For transforming the points on the canvas.
9 | - [projection](./projections)
10 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/anchor.mdx:
--------------------------------------------------------------------------------
1 | import Anchor from "@site/cetz/docs/_generated/draw/grouping/anchor.mdx";
2 |
3 | # anchor
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/copy-anchors.mdx:
--------------------------------------------------------------------------------
1 | import CopyAnchors from "@site/cetz/docs/_generated/draw/grouping/copy-anchors.mdx";
2 |
3 | # copy-anchors
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/floating.mdx:
--------------------------------------------------------------------------------
1 | import Floating from "@site/cetz/docs/_generated/draw/grouping/floating.mdx";
2 |
3 | # floating
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/for-each-anchor.mdx:
--------------------------------------------------------------------------------
1 | import ForEachAnchor from "@site/cetz/docs/_generated/draw/grouping/for-each-anchor.mdx";
2 |
3 | # for-each-anchor
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/get-ctx.mdx:
--------------------------------------------------------------------------------
1 | import GetCtx from "@site/cetz/docs/_generated/draw/grouping/get-ctx.mdx";
2 |
3 | # get-ctx
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/group.mdx:
--------------------------------------------------------------------------------
1 | import Group from "@site/cetz/docs/_generated/draw/grouping/group.mdx";
2 |
3 | # group
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/grouping.md:
--------------------------------------------------------------------------------
1 | # Grouping
2 |
3 | Draw functions that allow collecting other draw functions together.
4 |
5 | - [hide](./hide) Hides an element.
6 | - [intersections](./intersections) Calculates the intersections between multiple elements.
7 | - [group](./group) Groups one or more elements together.
8 | - [anchor](./anchor) Creates a new anchor for the current group.
9 | - [copy-anchors](./copy-anchors) Copies multiple anchors from one element into the current group.
10 | - [set-ctx](./set-ctx) Allows modifying the current canvas context.
11 | - [get-ctx](./get-ctx) Allows the reading of the current canvas context.
12 | - [for-each-anchor](./for-each-anchor) Iterates throguh all named anchors of an element with a callback.
13 | - [on-layer](./on-layer) Places elements on a specific layer.
14 | - [floating](./floating) Places an element without affecting bounding boxes.
15 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/hide.mdx:
--------------------------------------------------------------------------------
1 | import Hide from "@site/cetz/docs/_generated/draw/grouping/hide.mdx";
2 |
3 | # hide
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/intersections.mdx:
--------------------------------------------------------------------------------
1 | import Intersections from "@site/cetz/docs/_generated/draw/grouping/intersections.mdx";
2 |
3 | # intersections
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/on-layer.mdx:
--------------------------------------------------------------------------------
1 | import OnLayer from "@site/cetz/docs/_generated/draw/grouping/on-layer.mdx";
2 |
3 | # on-layer
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/scope.mdx:
--------------------------------------------------------------------------------
1 | import Scope from "@site/cetz/docs/_generated/draw/grouping/scope.mdx";
2 |
3 | # scope
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/grouping/set-ctx.mdx:
--------------------------------------------------------------------------------
1 | import SetCtx from "@site/cetz/docs/_generated/draw/grouping/set-ctx.mdx";
2 |
3 | # set-ctx
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/projections/on-xy.mdx:
--------------------------------------------------------------------------------
1 | import OnXY from "@site/cetz/docs/_generated/draw/projection/on-xy.mdx";
2 |
3 | # on-xy
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/projections/on-xz.mdx:
--------------------------------------------------------------------------------
1 | import OnXZ from "@site/cetz/docs/_generated/draw/projection/on-xz.mdx";
2 |
3 | # on-xz
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/projections/on-yz.mdx:
--------------------------------------------------------------------------------
1 | import OnYZ from "@site/cetz/docs/_generated/draw/projection/on-yz.mdx";
2 |
3 | # on-yz
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/projections/ortho.mdx:
--------------------------------------------------------------------------------
1 | import Ortho from "@site/cetz/docs/_generated/draw/projection/ortho.mdx";
2 |
3 | # ortho
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/projections/projections.md:
--------------------------------------------------------------------------------
1 | # Projection
2 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/arc.mdx:
--------------------------------------------------------------------------------
1 | import Arc from "@site/cetz/docs/_generated/draw/shapes/arc.mdx";
2 | import ArcThrough from "@site/cetz/docs/_generated/draw/shapes/arc-through.mdx";
3 |
4 | # arc
5 |
6 |
7 |
8 | ## arc-through
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/bezier.mdx:
--------------------------------------------------------------------------------
1 | import Bezier from "@site/cetz/docs/_generated/draw/shapes/bezier.mdx";
2 | import BezierThrough from "@site/cetz/docs/_generated/draw/shapes/bezier-through.mdx";
3 |
4 | # bezier
5 |
6 |
7 |
8 | ## bezier-through
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/catmull.mdx:
--------------------------------------------------------------------------------
1 | import Catmull from "@site/cetz/docs/_generated/draw/shapes/catmull.mdx";
2 |
3 | # catmull
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/circle.mdx:
--------------------------------------------------------------------------------
1 | import Circle from "@site/cetz/docs/_generated/draw/shapes/circle.mdx";
2 | import CircleThrough from "@site/cetz/docs/_generated/draw/shapes/circle-through.mdx";
3 |
4 | # circle
5 |
6 |
7 |
8 | ## circle-through
9 |
10 |
11 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/content.mdx:
--------------------------------------------------------------------------------
1 | import Content from "@site/cetz/docs/_generated/draw/shapes/content.mdx";
2 |
3 | # content
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/grid.mdx:
--------------------------------------------------------------------------------
1 | import Grid from "@site/cetz/docs/_generated/draw/shapes/grid.mdx";
2 |
3 | # grid
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/hobby.mdx:
--------------------------------------------------------------------------------
1 | import Hobby from "@site/cetz/docs/_generated/draw/shapes/hobby.mdx";
2 |
3 | # hobby
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/line.mdx:
--------------------------------------------------------------------------------
1 | import Line from "@site/cetz/docs/_generated/draw/shapes/line.mdx";
2 |
3 | # line
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/mark.mdx:
--------------------------------------------------------------------------------
1 | import Mark from "@site/cetz/docs/_generated/draw/shapes/mark.mdx";
2 |
3 | # mark
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/merge-path.mdx:
--------------------------------------------------------------------------------
1 | import MergePath from "@site/cetz/docs/_generated/draw/shapes/merge-path.mdx";
2 |
3 | # merge-path
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/polygon.mdx:
--------------------------------------------------------------------------------
1 | import Polygon from "@site/cetz/docs/_generated/draw/shapes/polygon.mdx";
2 |
3 | # polygon
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/rect.mdx:
--------------------------------------------------------------------------------
1 | import Rect from "@site/cetz/docs/_generated/draw/shapes/rect.mdx";
2 |
3 | # rect
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/shapes/shapes.md:
--------------------------------------------------------------------------------
1 | # Shapes
2 |
3 | Draw functions that draw shapes onto the canvas, be that lines, circles or curves.
4 |
5 | - [circle](./circle) Draws a circle at a point.
6 | - [arc](./arc) Draws an arc between two points.
7 | - [mark](./mark) Draws a mark at a point in a direction.
8 | - [line](./line) Draws a line between two points, or a line strip between 3 or more points.
9 | - [polygon](./polygon) Draws a regular polygon.
10 | - [grid](./grid) Draws a grid.
11 | - [content](./content) Places some content on the canvas.
12 | - [rect](./rect) Draws a rectangle between two points.
13 | - [bezier](./bezier) Draws a bezier with control points.
14 | - [hobby](./hobby) Draws a hobby curve.
15 | - [catmull](./catmull) Draws a Catmull-Rom curve.
16 | - [merge-path](./merge-path) Merges the paths of other draw functions into one continuous path.
17 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/styling/fill.mdx:
--------------------------------------------------------------------------------
1 | import Fill from "@site/cetz/docs/_generated/draw/styling/fill.mdx";
2 |
3 | # fill
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/styling/set-style.mdx:
--------------------------------------------------------------------------------
1 | import SetStyle from "@site/cetz/docs/_generated/draw/styling/set-style.mdx";
2 |
3 | # set-style
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/styling/stroke.mdx:
--------------------------------------------------------------------------------
1 | import Stroke from "@site/cetz/docs/_generated/draw/styling/stroke.mdx";
2 |
3 | # stroke
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/styling/styling.md:
--------------------------------------------------------------------------------
1 | # Styling
2 |
3 | Draw functions that change how other elements are drawn.
4 |
5 | - [set-style](./set-style) Sets the styling for elements.
6 | - [fill](./fill) Shorthand to set the fill of elements.
7 | - [stroke](./stroke) Shorthand to set the stroke of elements.
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/move-to.mdx:
--------------------------------------------------------------------------------
1 | import MoveTo from "@site/cetz/docs/_generated/draw/transformations/move-to.mdx";
2 |
3 | # move-to
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/rotate.mdx:
--------------------------------------------------------------------------------
1 | import Rotate from "@site/cetz/docs/_generated/draw/transformations/rotate.mdx";
2 |
3 | # rotate
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/scale.mdx:
--------------------------------------------------------------------------------
1 | import Scale from "@site/cetz/docs/_generated/draw/transformations/scale.mdx";
2 |
3 | # scale
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/set-origin.mdx:
--------------------------------------------------------------------------------
1 | import SetOrigin from "@site/cetz/docs/_generated/draw/transformations/set-origin.mdx";
2 |
3 | # set-origin
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/set-transform.mdx:
--------------------------------------------------------------------------------
1 | import SetTransform from "@site/cetz/docs/_generated/draw/transformations/set-transform.mdx";
2 |
3 | # set-transform
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/set-viewport.mdx:
--------------------------------------------------------------------------------
1 | import SetViewport from "@site/cetz/docs/_generated/draw/transformations/set-viewport.mdx";
2 |
3 | # set-viewport
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/transformations.md:
--------------------------------------------------------------------------------
1 | # Transformations
2 |
3 | All transformation functions push a transformation matrix onto the current transform stack. To apply transformations scoped use the [`group`](../grouping/group.mdx) draw function.
4 |
5 | Transformation matrices get multiplied in the following order:
6 |
7 | $$
8 | M_{\text{world}} = M_\text{world} \cdot M_\text{local}
9 | $$
10 |
--------------------------------------------------------------------------------
/docs/api/draw-functions/transformations/translate.mdx:
--------------------------------------------------------------------------------
1 | import Translate from "@site/cetz/docs/_generated/draw/transformations/translate.mdx";
2 |
3 | # translate
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/aabb.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Aabb
3 | ---
4 |
5 | # {{aabb}}
6 |
7 | An Axis Aligned Bounding Box, or AABB for short.
8 |
9 | They take the form of a dictionary with the following keys:
10 |
11 | - low vector: Min. bounds vector
12 | - high vector: Max. bounds vector
13 |
14 | The following functions are in the `aabb` module.
15 |
16 | import Combined from "@site/cetz/docs/_generated/aabb/-combined.mdx";
17 |
18 |
19 |
--------------------------------------------------------------------------------
/docs/api/internal/anchor.mdx:
--------------------------------------------------------------------------------
1 | # Anchor
2 |
3 | Functions to aid in anchor creation when defining custom elements.
4 |
5 | import Combined from "@site/cetz/docs/_generated/anchor/-combined.mdx";
6 |
7 |
8 |
--------------------------------------------------------------------------------
/docs/api/internal/bezier.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Bezier
3 | ---
4 |
5 | # {{bezier}}
6 |
7 | An array of three or four vectors, the start point, the endpoint, the first control point and optionally a second control point if the bezier is cubic.
8 |
9 | The following functions are in the `bezier` module.
10 |
11 | import Combined from "@site/cetz/docs/_generated/bezier/-combined.mdx";
12 |
13 |
14 |
--------------------------------------------------------------------------------
/docs/api/internal/canvas.mdx:
--------------------------------------------------------------------------------
1 | # canvas
2 |
3 | import Combined from "@site/cetz/docs/_generated/canvas/canvas.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/complex.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Complex
3 | ---
4 |
5 | # {{complex}}
6 |
7 | A complex number that takes the form of an {{array}} of two {{float}}s. The first element is the real number and the second represents the imaginary.
8 |
9 | import Combined from "@site/cetz/docs/_generated/complex/-combined.mdx";
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/api/internal/coordinate.mdx:
--------------------------------------------------------------------------------
1 | # Coordinate
2 |
3 | Functions to aid in resolving coordinates.
4 |
5 | import Combined from "@site/cetz/docs/_generated/coordinate/-combined.mdx";
6 |
7 |
8 |
--------------------------------------------------------------------------------
/docs/api/internal/drawable.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Drawable
3 | ---
4 |
5 | # {{drawable}}
6 |
7 | A dictionary that contains path or content data that will actually get drawn by the canvas. Can also be an array of this type.
8 |
9 | import Combined from "@site/cetz/docs/_generated/drawable/-combined.mdx";
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/api/internal/hobby.mdx:
--------------------------------------------------------------------------------
1 | # Hobby
2 |
3 | import Combined from "@site/cetz/docs/_generated/hobby/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/internal.md:
--------------------------------------------------------------------------------
1 | # Internal
2 |
--------------------------------------------------------------------------------
/docs/api/internal/intersection.mdx:
--------------------------------------------------------------------------------
1 | # Intersection
2 |
3 | import Combined from "@site/cetz/docs/_generated/intersection/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/mark.mdx:
--------------------------------------------------------------------------------
1 | # Mark
2 |
3 | import Combined from "@site/cetz/docs/_generated/mark/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/matrix.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Matrix
3 | ---
4 |
5 | # {{matrix}}
6 |
7 | An array of arrays of floats that represent a matrix. Can be any size but transformation matrices are 4x4.
8 |
9 | import Combined from "@site/cetz/docs/_generated/matrix/-combined.mdx";
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/api/internal/path-util.mdx:
--------------------------------------------------------------------------------
1 | # Path Util
2 |
3 | import Combined from "@site/cetz/docs/_generated/path-util/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/process.mdx:
--------------------------------------------------------------------------------
1 | # Process
2 |
3 | import Combined from "@site/cetz/docs/_generated/process/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/styles.mdx:
--------------------------------------------------------------------------------
1 | # Styles
2 |
3 | import Combined from "@site/cetz/docs/_generated/styles/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/util.mdx:
--------------------------------------------------------------------------------
1 | # Util
2 |
3 | import Combined from "@site/cetz/docs/_generated/util/-combined.mdx";
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/internal/vector.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Vector
3 | ---
4 |
5 | # {{vector}}
6 |
7 | An array of any number of floats.
8 |
9 | import Combined from "@site/cetz/docs/_generated/vector/-combined.mdx";
10 |
11 |
12 |
--------------------------------------------------------------------------------
/docs/api/libraries/angle/angle.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /api/libraries/angle/angle
3 | ---
4 |
5 | import Angle from "@site/cetz/docs/_generated/lib/angle/angle.mdx";
6 |
7 | # Angle
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/api/libraries/angle/index.md:
--------------------------------------------------------------------------------
1 | # Angle
2 |
3 | Provides helper functions to draw angles and right angles.
4 |
--------------------------------------------------------------------------------
/docs/api/libraries/angle/right-angle.mdx:
--------------------------------------------------------------------------------
1 | import RightAngle from "@site/cetz/docs/_generated/lib/angle/right-angle.mdx";
2 |
3 | # Right Angle
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/braces/brace.mdx:
--------------------------------------------------------------------------------
1 | import Brace from "@site/cetz/docs/_generated/lib/decorations/brace/brace.mdx";
2 |
3 | # Brace
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/braces/flat-brace.mdx:
--------------------------------------------------------------------------------
1 | import FlatBrace from "@site/cetz/docs/_generated/lib/decorations/brace/flat-brace.mdx";
2 |
3 | # Flat Brace
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/braces/index.md:
--------------------------------------------------------------------------------
1 | # Braces
2 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/index.md:
--------------------------------------------------------------------------------
1 | # Decorations
2 |
3 | Various pre-made shapes and path modifications.
4 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/path/coil.mdx:
--------------------------------------------------------------------------------
1 | import Coil from "@site/cetz/docs/_generated/lib/decorations/path/coil.mdx";
2 |
3 | # Coil
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/path/index.mdx:
--------------------------------------------------------------------------------
1 | # Path Decorations
2 |
3 | Path decorations are elements that accept a path as input and generate one or more shapes that follow that path.
4 |
5 | All path decoration functions support the following style keys:
6 |
7 |
8 | Absolute or relative start of the decoration on the path.
9 |
10 |
11 |
12 | Absolute or relative end of the decoration on the path.
13 |
14 |
15 |
16 | If set to `"LINE"`, generate lines between the path's start/end and the
17 | decoration's start/end if the path is *not closed*.
18 |
19 |
20 |
21 | Width or thickness of the decoration.
22 |
23 |
24 |
25 | The number of repetitions/phases to generate. This key is ignored if
26 | `segment-length` is not none
27 |
28 |
29 |
30 | Length of one repetion/phase of the decoration.
31 |
32 |
33 |
34 | Alignment of the decoration on the path *if `segment-length` is set* and the
35 | decoration does not fill up the full range between start and stop. Can be one
36 | of `"START"`, `"MID"`, `"END`.
37 |
38 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/path/wave.mdx:
--------------------------------------------------------------------------------
1 | import Wave from "@site/cetz/docs/_generated/lib/decorations/path/wave.mdx";
2 |
3 | # Wave
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/decorations/path/zigzag.mdx:
--------------------------------------------------------------------------------
1 | import Zigzag from "@site/cetz/docs/_generated/lib/decorations/path/zigzag.mdx";
2 |
3 | # Zigzag
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/index.md:
--------------------------------------------------------------------------------
1 | # Libraries
2 |
3 | Functions of CeTZ's libraries.
4 |
--------------------------------------------------------------------------------
/docs/api/libraries/palette/index.mdx:
--------------------------------------------------------------------------------
1 | # Palette
2 |
3 | A palette is a function of the form `index => style` that takes an index, that can be any int and returns a canvas style dictionary. If passed the string `"len"` it must return the length of its unique styles. An example use for palette functions is the plot library, which can use palettes to apply different styles per plot.
4 |
5 | ## Predefined Palettes
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/palette/new.mdx:
--------------------------------------------------------------------------------
1 | import New from "@site/cetz/docs/_generated/lib/palette/new.mdx";
2 |
3 | # New
4 |
5 |
6 |
--------------------------------------------------------------------------------
/docs/api/libraries/tree/index.md:
--------------------------------------------------------------------------------
1 | # Tree
2 |
3 | The tree library allows the drawing diagrams with simple tree layout algorithms.
4 |
--------------------------------------------------------------------------------
/docs/api/libraries/tree/tree.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /api/libraries/tree/tree
3 | ---
4 |
5 | import Tree from "@site/cetz/docs/_generated/lib/tree/tree.mdx";
6 |
7 | # Tree
8 |
9 |
10 |
--------------------------------------------------------------------------------
/docs/api/overview.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | This section is a reference for all functions in the CeTZ package and its libraries.
4 |
--------------------------------------------------------------------------------
/docs/basics/anchors.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Anchors
3 | ---
4 |
5 | import Type from "@site/src/components/Type";
6 |
7 | You can refer to a position relative to an element by using its anchors. Anchors come in three different variations but can all be used in two ways.
8 |
9 | The first is by using the `anchor` argument on an element. When given, the element will be translated such that the given anchor will be where the given position is. This is supported by all elements that have the `anchor` argument.
10 |
11 | ```typc example
12 | // Draw a circle and place its "west" anchor at the origin.
13 | circle((0,0), anchor: "west")
14 |
15 | // Draw a smaller red circle at the origin.
16 | fill(red)
17 | stroke(none)
18 | circle((0,0), radius: 0.3)
19 | ```
20 |
21 | The second is by using [anchor coordinates](/basics/coordinate-systems#anchor). You must first give the element a name by passing a string to its `name` argument, you can then use its anchors to place other elements. Note that this is only available for elements that have a `name` argument.
22 |
23 | ```typc example
24 | // Name the circle
25 | circle((0,0), name: "circle")
26 |
27 | // Draw a smaller red circle at "circle"'s east anchor
28 | fill(red)
29 | stroke(none)
30 | circle("circle.east", radius: 0.3)
31 | ```
32 |
33 | ## Named
34 |
35 | Named anchors are normally unique to the type of element, such as a bezier curve's control points. Other border and path anchors specify their own named anchors that are available to all elements that support border or path anchors.
36 |
37 | Elements that have an `anchor` argument also have a "default" named anchor. You can use it by just giving the element's name without an anchor.
38 |
39 | ## Border
40 |
41 | A border anchor refers to a point on the element's border where a ray is cast from the element's center at a given angle and hits the border.
42 |
43 | They are given as angles where `0deg` is towards the right and `90deg` is up.
44 |
45 | Border anchors also specify named compass directions such as "north", "north-east", etc. Border anchors also specify a "center" named anchor which is where the ray cast originates from.
46 |
47 | ```typc example
48 | circle((0, 0), name: "circle", radius: 1)
49 |
50 | set-style(content: (frame: "rect", stroke: none, fill: white, padding: .1))
51 | content((name: "circle", anchor: 0deg), [0deg], anchor: "west")
52 | content((name: "circle", anchor: 160deg), [160deg], anchor: "south-east")
53 | content("circle.north", [North], anchor: "south")
54 | content("circle.south-east", [South East], anchor: "north-west")
55 | content("circle.south-west", [South West], anchor: "north-east")
56 | ```
57 |
58 | ## Path
59 |
60 | A path anchor refers to a point along the path of an element. They can be given as either a number for an absolute distance along the path, or a ratio for a relative distance along the path.
61 |
62 | Path anchors also specify three anchors "start", "mid" and "end".
63 |
64 | ```typc example
65 | line((0,0), (10, 1), name: "line")
66 |
67 | set-style(content: (frame: "rect", stroke: none, fill: white, padding: .1))
68 | content("line.start", [0%, 0, "start"], anchor: "east")
69 | content("line.mid", [50%, "mid"])
70 | content("line.end", [100%, "end"], anchor: "west")
71 |
72 | content((name: "line", anchor: 75%), [75%])
73 | content((name: "line", anchor: 50pt), [50pt])
74 | ```
75 |
--------------------------------------------------------------------------------
/docs/basics/basics.md:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | # Basics
5 |
6 | The following chapters are about the basic and core concepts of CeTZ. They are recommended reading for basic usage.
7 |
--------------------------------------------------------------------------------
/docs/basics/canvas.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: The Canvas
3 | ---
4 |
5 | The [`canvas`](/api/internal/canvas) function is what handles all of the logic and processing in order to produce drawings. It's usually called with a code block `{...}` as argument. The content of the curly braces is the _body_ of the canvas. Import all the draw functions you need at the top of the body:
6 |
7 | ```typ
8 | #cetz.canvas({
9 | import cetz.draw: *
10 |
11 | })
12 | ```
13 |
14 | You can now call the draw functions within the body and they'll produce some graphics! Typst will evaluate the code block and pass the result to the `canvas` function for rendering.
15 |
16 | The canvas does not have typical `width` and `height` parameters. Instead its size will grow and shrink to fit the drawn graphic.
17 |
18 | By default 1 [coordinate](/basics/coordinate-systems) unit is `1cm`, this can be changed by setting the `length` parameter. If a ratio is given, the length will be the size of the canvas' parent's width!
19 |
--------------------------------------------------------------------------------
/docs/basics/custom-types.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | import Type from "@site/src/components/Type";
5 |
6 | # Custom Types
7 |
8 | Many CeTZ functions expect data in certain formats which we will call types. Note that these are actually made up of Typst primitives.
9 |
10 | ## coordinate
11 |
12 | A position on the canvas specified by any coordinate system. See [Coordinate Systems](/basics/coordinate-systems).
13 |
14 | ## number
15 |
16 | Any of float, int or length.
17 |
18 | ## style
19 |
20 | Represents options passed to draw functions that affect how elements are drawn. They are normally taken in the form of named arguments to the draw functions or sometimes can be a dictionary for a single argument.
21 |
22 |
--------------------------------------------------------------------------------
/docs/basics/styling.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Styling
3 | ---
4 |
5 |
6 | import Parameter from "@site/src/components/Parameter";
7 | import Type from "@site/src/components/Type";
8 |
9 | You can style draw elements by passing the relevant named arguments to their draw functions. All elements that draw something have stroke and fill styling unless said otherwise.
10 |
11 |
12 | How to fill the drawn element.
13 |
14 |
19 | How to stroke the border or the path of the draw element. [See Typst's line
20 | documentation for more
21 | details.](https://typst.app/docs/reference/visualize/line/#parameters-stroke)
22 |
23 |
24 | How to fill self-intersecting paths. Can be "non-zero" or "even-odd".
25 | [See Typst's path documentation for more details.](https://typst.app/docs/reference/visualize/path/#parameters-fill-rule)
26 |
27 |
28 |
29 |
30 | ```typc example
31 | // Draws a red circle with a blue border
32 | circle((0, 0), fill: red, stroke: blue)
33 |
34 | // Draws a green line
35 | line((0, 0), (1, 1), stroke: green)
36 | ```
37 |
38 | Instead of having to specify the same styling for each time you want to draw an element, you can use the [`set-style`](/api/draw-functions/styling/set-style) function to change the style for all elements after it, like a Typst `set` rule. You can still pass styling to a draw function to override what has been set with `set-style`. You can also use the [`fill`](/api/draw-functions/styling/fill) and [`stroke`](/api/draw-functions/styling/stroke) functions as a shorthand to set the fill and stroke respectively.
39 |
40 | ```typc example
41 | // Draws an empty square with a black border
42 | rect((-1, -1), (1, 1))
43 |
44 | // Sets the global style to have a fill of red and a stroke of blue
45 | set-style(stroke: blue, fill: red)
46 | circle((0,0))
47 |
48 | // Draws a green line despite the global stroke being blue
49 | line((), (1,1), stroke: green)
50 | ```
51 |
52 | When using a dictionary for a style, it is important to note that they update each other instead of overriding the entire option like a non-dictionary value would. For example, if the stroke is set to `(paint: red, thickness: 5pt)` and you pass `(paint: blue)`, the stroke would become `(paint: blue, thickness: 5pt)`.
53 |
54 | ```typc example
55 | // Sets the stroke to red with a thickness of 5pt
56 | set-style(stroke: (paint: red, thickness: 5pt))
57 |
58 | // Draws a line with the global stroke
59 | line((0,0), (1,0))
60 |
61 | // Draws a blue line with a thickness of 5pt because dictionaries update the style
62 | line((0,0), (1,1), stroke: (paint: blue))
63 |
64 | // Draws a yellow line with a thickness of 1pt because other values override the style
65 | line((0,0), (0,1), stroke: yellow)
66 | ```
67 |
68 | You can also specify styling for each type of element. Note that dictionary values will still update with its global value, the full hierarchy is `function > element type > global`. When the value of a style is auto, it will become exactly its parent style.
69 |
70 | ```typc example
71 | set-style(
72 | // Global fill and stroke
73 | fill: green,
74 | stroke: (thickness: 5pt),
75 | // Stroke and fill for only rectangles
76 | rect: (stroke: (dash: "dashed"), fill: blue),
77 | )
78 | rect((0,0), (1,1))
79 | circle((2.5, 0.5))
80 | rect((4, 0), (5, 1), stroke: (thickness: 1pt))
81 | ```
82 |
--------------------------------------------------------------------------------
/docs/custom-types.js:
--------------------------------------------------------------------------------
1 | export default {
2 | number: { link: "/docs/basics/custom-types#number", class: "num" },
3 | coordinate: { link: "/docs/basics/custom-types#coordinate" },
4 | style: { link: "/docs/basics/custom-types#style" },
5 | context: { link: "/docs/advanced/custom-types#context" },
6 | vector: { link: "/docs/api/internal/vector" },
7 | matrix: { link: "/docs/api/internal/matrix" },
8 | element: {link: "/docs/advanced/custom-types#element"},
9 | };
10 |
--------------------------------------------------------------------------------
/docs/getting-started.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Getting Started
3 | sidebar_position: 1
4 | ---
5 |
6 | ## Usage
7 |
8 | This is the minimal starting point in a `.typ` file:
9 |
10 | ```typ
11 | #import "@preview/cetz:0.3.4"
12 | #cetz.canvas({
13 | import cetz.draw: *
14 | ...
15 | })
16 | ```
17 |
18 | Note that draw functions are imported inside the scope of the `canvas` block. This is recommended as some draw functions override Typst's functions such as `line`.
19 |
20 | ## Examples
21 |
22 | From this point on only the code inside the `canvas` block will be shown in examples unless specified otherwise.
23 |
24 | ```typc example
25 | circle((0, 0))
26 | line((0, 0), (2, 1))
27 | ```
28 |
--------------------------------------------------------------------------------
/docs/internals/internals.md:
--------------------------------------------------------------------------------
1 | # Internals
2 |
3 | CeTZ is made up of several parts which can be daunting and complicated to figure out. Here we plan to detail how CeTZ actually works and explain the ideas.
4 |
5 | This is not required reading for typical usage!
6 |
--------------------------------------------------------------------------------
/docs/libraries/libraries.md:
--------------------------------------------------------------------------------
1 | ---
2 | title: Libraries
3 | ---
4 |
5 | CeTZ provides more specialised and focused functions in order to draw plots, charts, angles etc. They have been separated from the `draw` module into separate libraries for the sake of organisation and clarity.
6 |
7 | We are planning to move them into their own packages. We don't know when but most likely once the current Typst package handling system gets improved.
8 |
--------------------------------------------------------------------------------
/docs/libraries/plot.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Plot
3 | ---
4 |
5 | import Type from "@site/src/components/Type";
6 |
7 | The plot library allows the plotting of data.
8 |
9 | ## Types
10 |
11 | The following types are commonly used by functions of this library
12 |
13 | ### domain
14 |
15 | A tuple representing a mathematical function's domain as a closed interval. Example domains are `(0, 1)` for $[0,1]$ or `(-calc.pi, calc.pi)` for $[-\pi, \pi]$.
16 |
17 | ### axes
18 |
19 | A tuple of axis names. Functions that take axes will use those axes as their `x` and `y` axis for plotting. To rotate a plot, you can simply swap its axes such as `("y", "x")`.
20 |
21 | ## Usage
22 |
23 | ...
24 |
--------------------------------------------------------------------------------
/docs/libraries/tree.mdx:
--------------------------------------------------------------------------------
1 | ---
2 | title: Tree
3 | ---
4 |
5 | import Type from "@site/src/components/Type";
6 |
7 | The tree library allows the drawing of diagrams with simple tree layout algorithms.
8 |
9 | ## Nodes
10 |
11 | A tree node is an array consisting of the node's value at index 0 followed by its child nodes. For the default `draw-node` function, the value (the first item) of a node must be of type content.
12 |
13 | Example of a list of nodes:
14 |
15 | ```typc example
16 | cetz.tree.tree(
17 | (
18 | [A],
19 | (
20 | [B],
21 | (
22 | [C],
23 | ([D],)
24 | )
25 | )
26 | ),
27 | direction: "right"
28 | )
29 | ```
30 |
31 | Example of a tree of nodes:
32 |
33 | ```typc example
34 | cetz.tree.tree(
35 | (
36 | [A],
37 | (
38 | [B],
39 | [C]
40 | ),
41 | (
42 | [D],
43 | [E]
44 | )
45 | ),
46 | direction: "right"
47 | )
48 | ```
49 |
50 | ## Drawing and Styling Tree Nodes
51 |
52 | The `tree()` function takes an optional `draw-node:` and `draw-edge:` callback function that can be used to customice node and edge drawing.
53 |
54 | The `draw-node` function must take the current node and its parents node anchor as arguments and return one or more elements.
55 |
56 | For drawing edges between nodes, the `draw-edge` function must take two node anchors and the target node as arguments and return one or more elements.
57 |
58 | ```typc example
59 | import cetz.tree
60 | let data = ([\*], ([A], [A.A], [A.B]), ([B], [B.A]))
61 | tree.tree(
62 | data,
63 | direction: "right",
64 | draw-node: (node, ..) => {
65 | circle((), radius: .35, fill: blue, stroke: none)
66 | content((), text(white, [#node.content]))
67 | },
68 | draw-edge: (from, to, ..) => {
69 | let (a, b) = (from + ".center", to + ".center")
70 | line((a, .4, b), (b, .4, a))
71 | }
72 | )
73 | ```
74 |
--------------------------------------------------------------------------------
/docs/overview.md:
--------------------------------------------------------------------------------
1 | ---
2 | slug: /
3 | sidebar_position: 0
4 | ---
5 |
6 | # Overview
7 |
8 | CeTZ, ein Typst Zeichenpaket, is a drawing package for [Typst](https://typst.app/). Its API is similar to Processing but with relative coordinates and anchors from Ti*k*Z. You also won't have to worry about accidentally drawing over other content as the canvas will automatically resize. And remember: up is positive!
9 |
10 | These docs are a work in progress! Please submit issues for parts that don't make sense or need improving :)
11 |
12 | We are also still trying to find a logo for CeTZ so if you have any ideas please let us know through the Typst discord server.
13 |
--------------------------------------------------------------------------------
/docs/sidebar.js:
--------------------------------------------------------------------------------
1 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
2 | export default [
3 | "overview",
4 | "getting-started",
5 | {
6 | type: "category",
7 | label: "Basics",
8 | link: {
9 | type: "doc",
10 | id: "basics/basics",
11 | },
12 | items: [
13 | "basics/custom-types",
14 | "basics/canvas",
15 | "basics/styling",
16 | "basics/coordinate-systems",
17 | "basics/anchors",
18 | "basics/marks",
19 | ],
20 | },
21 | {
22 | type: "category",
23 | label: "Libraries",
24 | link: {
25 | type: "doc",
26 | id: "libraries/libraries",
27 | },
28 | items: ["libraries/tree"],
29 | },
30 | {
31 | type: "category",
32 | label: "Tutorials",
33 | link: {
34 | type: "generated-index",
35 | title: "Tutorials",
36 | },
37 | items: ["tutorials/karl"],
38 | },
39 | {
40 | type: "category",
41 | label: "Advanced",
42 | link: {
43 | type: "doc",
44 | id: "advanced/advanced",
45 | },
46 | items: ["advanced/custom-types"],
47 | },
48 | ];
49 |
--------------------------------------------------------------------------------
/gallery/karls-picture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/gallery/karls-picture.png
--------------------------------------------------------------------------------
/gallery/karls-picture.typ:
--------------------------------------------------------------------------------
1 | #import "@preview/cetz:0.3.4"
2 | #set page(width: auto, height: auto, margin: .5cm)
3 |
4 | #show math.equation: block.with(fill: white, inset: 1pt)
5 |
6 | #cetz.canvas(length: 3cm, {
7 | import cetz.draw: *
8 |
9 | set-style(
10 | mark: (fill: black, scale: 2),
11 | stroke: (thickness: 0.4pt, cap: "round"),
12 | angle: (
13 | radius: 0.3,
14 | label-radius: .22,
15 | fill: green.lighten(80%),
16 | stroke: (paint: green.darken(50%))
17 | ),
18 | content: (padding: 1pt)
19 | )
20 |
21 | grid((-1.5, -1.5), (1.4, 1.4), step: 0.5, stroke: gray + 0.2pt)
22 |
23 | circle((0,0), radius: 1)
24 |
25 | line((-1.5, 0), (1.5, 0), mark: (end: "stealth"))
26 | content((), $ x $, anchor: "west")
27 | line((0, -1.5), (0, 1.5), mark: (end: "stealth"))
28 | content((), $ y $, anchor: "south")
29 |
30 | for (x, ct) in ((-1, $ -1 $), (-0.5, $ -1/2 $), (1, $ 1 $)) {
31 | line((x, 3pt), (x, -3pt))
32 | content((), anchor: "north", ct)
33 | }
34 |
35 | for (y, ct) in ((-1, $ -1 $), (-0.5, $ -1/2 $), (0.5, $ 1/2 $), (1, $ 1 $)) {
36 | line((3pt, y), (-3pt, y))
37 | content((), anchor: "east", ct)
38 | }
39 |
40 | // Draw the green angle
41 | cetz.angle.angle((0,0), (1,0), (1, calc.tan(30deg)),
42 | label: text(green, [#sym.alpha]))
43 |
44 | line((0,0), (1, calc.tan(30deg)))
45 |
46 | set-style(stroke: (thickness: 1.2pt))
47 |
48 | line((30deg, 1), ((), "|-", (0,0)), stroke: (paint: red), name: "sin")
49 | content(("sin.start", 50%, "sin.end"), text(red)[$ sin alpha $])
50 | line("sin.end", (0,0), stroke: (paint: blue), name: "cos")
51 | content(("cos.start", 50%, "cos.end"), text(blue)[$ cos alpha $], anchor: "north")
52 | line((1, 0), (1, calc.tan(30deg)), name: "tan", stroke: (paint: orange))
53 | content("tan.end", $ text(#orange, tan alpha) = text(#red, sin alpha) / text(#blue, cos alpha) $, anchor: "west")
54 | })
55 |
--------------------------------------------------------------------------------
/gallery/paciolis.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/gallery/paciolis.png
--------------------------------------------------------------------------------
/gallery/paciolis.typ:
--------------------------------------------------------------------------------
1 | // Example by @samuelireson
2 | #import "@preview/cetz:0.3.4": canvas, draw, tree
3 |
4 | #set page(width: auto, height: auto, margin: .5cm)
5 |
6 | #canvas(length: 2cm, {
7 | import draw: *
8 | let phi = (1 + calc.sqrt(5)) / 2
9 |
10 | ortho({
11 | hide({
12 | line(
13 | (-phi, -1, 0), (-phi, 1, 0), (phi, 1, 0), (phi, -1, 0), close: true, name: "xy",
14 | )
15 | line(
16 | (-1, 0, -phi), (1, 0, -phi), (1, 0, phi), (-1, 0, phi), close: true, name: "xz",
17 | )
18 | line(
19 | (0, -phi, -1), (0, -phi, 1), (0, phi, 1), (0, phi, -1), close: true, name: "yz",
20 | )
21 | })
22 |
23 | intersections("a", "yz", "xy")
24 | intersections("b", "xz", "yz")
25 | intersections("c", "xy", "xz")
26 |
27 | set-style(stroke: (thickness: 0.5pt, cap: "round", join: "round"))
28 | line((0, 0, 0), "c.1", (phi, 1, 0), (phi, -1, 0), "c.3")
29 | line("c.0", (-phi, 1, 0), "a.2")
30 | line((0, 0, 0), "b.1", (1, 0, phi), (-1, 0, phi), "b.3")
31 | line("b.0", (1, 0, -phi), "c.2")
32 | line((0, 0, 0), "a.1", (0, phi, 1), (0, phi, -1), "a.3")
33 | line("a.0", (0, -phi, 1), "b.2")
34 |
35 | anchor("A", (0, phi, 1))
36 | content("A", [$A$], anchor: "north", padding: .1)
37 | anchor("B", (-1, 0, phi))
38 | content("B", [$B$], anchor: "south", padding: .1)
39 | anchor("C", (1, 0, phi))
40 | content("C", [$C$], anchor: "south", padding: .1)
41 | line("A", "B", stroke: (dash: "dashed"))
42 | line("A", "C", stroke: (dash: "dashed"))
43 | })
44 | })
45 |
--------------------------------------------------------------------------------
/gallery/periodic-table.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/gallery/periodic-table.png
--------------------------------------------------------------------------------
/gallery/plate-capacitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/gallery/plate-capacitor.png
--------------------------------------------------------------------------------
/gallery/plate-capacitor.typ:
--------------------------------------------------------------------------------
1 | // Copied from https://github.com/janosh/tikz/blob/87754ea/assets/plate-capacitor/plate-capacitor.typ
2 |
3 | #import "@preview/cetz:0.3.4": canvas, draw
4 | #import draw: line, rect, content, bezier, group, anchor
5 |
6 | #set page(width: auto, height: auto, margin: 5pt)
7 |
8 | // Constants
9 | #let height = 5
10 | #let width = 4
11 | #let plate-width = 0.5
12 | #let diel-width = 0.16 * width
13 | #let n-field-lines = 7
14 | #let n-charges = 7
15 |
16 | // Colors
17 | #let e-color = rgb("#e67300")
18 | #let plus-color = rgb("#cc2200").transparentize(20%)
19 | #let minus-color = rgb("#0044cc").transparentize(20%)
20 |
21 | // Helper function to draw a capacitor plate with charges
22 | #let plate(x, is-anode: true) = {
23 | let color = if is-anode { plus-color } else { minus-color }
24 | let fill-base = if is-anode { rgb("#f29797") } else { rgb("#9fc2f6") }
25 | let sign = if is-anode { $+$ } else { $-$ }
26 |
27 | // Draw plate with gradient fill
28 | rect(
29 | (x, 0),
30 | (x + plate-width, height),
31 | stroke: (paint: color, thickness: .7pt),
32 | fill: gradient.linear(fill-base.lighten(50%), fill-base, angle: 90deg),
33 | )
34 | // Draw charge label
35 | content(
36 | (x + plate-width / 2, height + 0.1),
37 | text(fill: color)[$sign Q_"C"$],
38 | anchor: "south",
39 | )
40 | // Draw charges
41 | for ii in range(n-charges) {
42 | let y = ii * height / n-charges + 0.325
43 | content((x + plate-width / 2, y), text(fill: color)[$sign$])
44 | }
45 | }
46 |
47 | // Helper function to draw a dipole
48 | #let dipole(x, y, ..style) = group({
49 | let plus-grad = gradient.linear(
50 | angle: 90deg,
51 | minus-color.lighten(30%),
52 | minus-color.darken(30%),
53 | )
54 | let minus-grad = gradient.linear(
55 | angle: 90deg,
56 | plus-color.lighten(30%),
57 | plus-color.darken(30%),
58 | )
59 | rect(x, ((x, "|-", y), 50%, y), fill: plus-grad, radius: (west: .5), name: "minus", ..style)
60 | rect(y, ((x, "-|", y), 50%, x), fill: minus-grad, radius: (east: .5), name: "plus", ..style)
61 | content("plus", [+])
62 | content("minus", [--])
63 | })
64 |
65 | #canvas({
66 | // Dielectric slab
67 | rect(
68 | (diel-width, -0.03 * height),
69 | (width - diel-width, 1.08 * height),
70 | stroke: e-color,
71 | fill: rgb("#fff8f0"), // very light orange
72 | )
73 | content((width / 2, 1.15 * height), text(fill: e-color)[$arrow(E)$])
74 | content((width * 0.8, 1.09 * height), text(fill: minus-color)[$+Q_"surf"$], anchor: "south")
75 | content((1.3 * diel-width, 1.09 * height), text(fill: plus-color)[$-Q_"surf"$], anchor: "south")
76 |
77 | // Electric field lines
78 | for ii in range(n-field-lines) {
79 | let y = (ii + 0.42) * height / n-field-lines
80 | line(
81 | (-plate-width, y),
82 | (width + plate-width, y),
83 | stroke: (paint: e-color, thickness: 1.2pt),
84 | mark: (pos: 0.5, end: "stealth", fill: e-color),
85 | )
86 | }
87 |
88 | // Draw plates
89 | plate(width, is-anode: false) // Left plate (cathode)
90 | plate(-plate-width, is-anode: true) // Right plate (anode)
91 |
92 | // Dipoles
93 | for x in (0.3, 0.5, 0.7) {
94 | for ii in range(n-field-lines) {
95 | let y = (ii + 0.94) * height / n-field-lines
96 | dipole((x * width - 0.3, y - 0.12), (x * width + 0.3, y + 0.12), stroke: 0.5pt)
97 | }
98 | }
99 | })
100 |
--------------------------------------------------------------------------------
/gallery/tree.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/gallery/tree.png
--------------------------------------------------------------------------------
/gallery/tree.typ:
--------------------------------------------------------------------------------
1 | #import "@preview/cetz:0.3.4": canvas, draw, tree
2 |
3 | #set page(width: auto, height: auto, margin: .5cm)
4 |
5 | #let data = (
6 | [A], ([B], [C], [D]), ([E], [F])
7 | )
8 |
9 | #canvas({
10 | import draw: *
11 |
12 | set-style(content: (padding: .2),
13 | fill: gray.lighten(70%),
14 | stroke: gray.lighten(70%))
15 |
16 | tree.tree(data, spread: 2.5, grow: 1.5, draw-node: (node, ..) => {
17 | circle((), radius: .45, stroke: none)
18 | content((), node.content)
19 | }, draw-edge: (from, to, ..) => {
20 | line((a: from, number: .6, b: to),
21 | (a: to, number: .6, b: from), mark: (end: ">"))
22 | }, name: "tree")
23 |
24 | // Draw a "custom" connection between two nodes
25 | let (a, b) = ("tree.0-0-1", "tree.0-1-0",)
26 | line((a, .6, b), (b, .6, a), mark: (end: ">", start: ">"))
27 | })
28 |
--------------------------------------------------------------------------------
/gallery/waves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/gallery/waves.png
--------------------------------------------------------------------------------
/gallery/waves.typ:
--------------------------------------------------------------------------------
1 | #import "@preview/cetz:0.3.4": canvas, draw, vector, matrix
2 |
3 | #set page(width: auto, height: auto, margin: .5cm)
4 |
5 | #canvas({
6 | import draw: *
7 |
8 | ortho(y: -30deg, x: 30deg, {
9 | on-xz({
10 | grid((0,-2), (8,2), stroke: gray + .5pt)
11 | })
12 |
13 | // Draw a sine wave on the xy plane
14 | let wave(amplitude: 1, fill: none, phases: 2, scale: 8, samples: 100) = {
15 | line(..(for x in range(0, samples + 1) {
16 | let x = x / samples
17 | let p = (2 * phases * calc.pi) * x
18 | ((x * scale, calc.sin(p) * amplitude),)
19 | }), fill: fill)
20 |
21 | let subdivs = 8
22 | for phase in range(0, phases) {
23 | let x = phase / phases
24 | for div in range(1, subdivs + 1) {
25 | let p = 2 * calc.pi * (div / subdivs)
26 | let y = calc.sin(p) * amplitude
27 | let x = x * scale + div / subdivs * scale / phases
28 | line((x, 0), (x, y), stroke: rgb(0, 0, 0, 150) + .5pt)
29 | }
30 | }
31 | }
32 |
33 | on-xy({
34 | wave(amplitude: 1.6, fill: rgb(0, 0, 255, 50))
35 | })
36 | on-xz({
37 | wave(amplitude: 1, fill: rgb(255, 0, 0, 50))
38 | })
39 | })
40 | })
41 |
--------------------------------------------------------------------------------
/justfile:
--------------------------------------------------------------------------------
1 | # Local Variables:
2 | # mode: makefile
3 | # End:
4 | gallery_dir := "./gallery"
5 |
6 | build:
7 | cd cetz-core; \
8 | cargo build --release \
9 | --target wasm32-unknown-unknown; \
10 | cp target/wasm32-unknown-unknown/release/cetz_core.wasm cetz_core.wasm
11 |
12 | package target *options:
13 | ./common/scripts/package "{{target}}" {{options}}
14 |
15 | install target="@local": build
16 | ./common/scripts/package "{{target}}"
17 |
18 | test *filter: build
19 | tt run {{filter}}
20 |
21 | update-test *filter:
22 | tt update {{filter}}
23 |
24 | gallery:
25 | for f in "{{gallery_dir}}"/*.typ; do typst c "$f" "${f/typ/png}"; done
26 |
--------------------------------------------------------------------------------
/requirements.typ:
--------------------------------------------------------------------------------
1 | #import "/src/deps.typ"
2 | #import "@preview/tidy:0.1.0"
3 | #import "@preview/tidy:0.2.0"
4 | #import "@preview/t4t:0.3.2"
5 |
--------------------------------------------------------------------------------
/src/aabb.typ:
--------------------------------------------------------------------------------
1 | #import "vector.typ"
2 | #let cetz-core = plugin("../cetz-core/cetz_core.wasm")
3 |
4 | /// Compute an axis aligned bounding box (aabb) for a list of vectors.
5 | ///
6 | /// - pts (array): List of vectors.
7 | /// - init (aabb): Initial aabb
8 | /// -> aabb
9 | #let aabb(pts, init: none) = {
10 | let args = (pts: pts, init: init)
11 | let encoded = cbor.encode(args)
12 | let bounds = cbor(cetz-core.aabb_func(encoded))
13 | return bounds
14 | }
15 |
16 | /// Get the mid-point of an AABB as vector.
17 | ///
18 | /// - bounds (aabb): The AABB to get the mid-point of.
19 | /// -> vector
20 | #let mid(bounds) = {
21 | return vector.scale(vector.add(bounds.low, bounds.high), .5)
22 | }
23 |
24 | /// Get the size of an aabb as vector. This is a vector from the aabb's low to high.
25 | ///
26 | /// - bounds (aabb): The aabb to get the size of.
27 | /// -> vector
28 | #let size(bounds) = {
29 | return vector.sub(bounds.high, bounds.low)
30 | }
31 |
32 | /// Pad AABB with padding from dictionary with keys top, left, right and bottom.
33 | ///
34 | /// - bounds (aabb): The AABB to pad.
35 | /// - padding (none, dictionary): Padding values
36 | ///
37 | /// -> aabb
38 | #let padded(bounds, padding) = {
39 | if padding != none {
40 | bounds.low.at(0) -= padding.at("left", default: 0)
41 | bounds.low.at(1) -= padding.at("top", default: 0)
42 | bounds.high.at(0) += padding.at("right", default: 0)
43 | bounds.high.at(1) += padding.at("bottom", default: 0)
44 | }
45 | return bounds
46 | }
47 |
--------------------------------------------------------------------------------
/src/complex.typ:
--------------------------------------------------------------------------------
1 | /// Returns the real part of a complex number.
2 | /// - V (complex): A complex number.
3 | /// -> float
4 | #let re(V) = V.at(0)
5 |
6 | /// Returns the imaginary part of a complex number.
7 | /// - V (complex): A complex number.
8 | /// -> float
9 | #let im(V) = V.at(1)
10 |
11 |
12 | /// Multiplies two complex numbers together and returns the result $V W$.
13 | /// - V (complex): The complex number on the left hand side.
14 | /// - W (complex): The complex number on the right hand side.
15 | #let mul(V, W) = (re(V) * re(W) - im(V) * im(W), im(V) * re(W) + re(V) * im(W))
16 |
17 | /// Calculates the conjugate of a complex number.
18 | /// - V (complex): A complex number.
19 | /// -> complex
20 | #let conj(V) = (re(V),-im(V))
21 |
22 | // TODO: check what "in R^2" means.
23 | /// Calculates the dot product of two complex numbers in R^2 $V \cdot W$.
24 | /// - V (complex): The complex number on the left hand side.
25 | /// - W (complex): The complex number on the right hand side.
26 | /// -> float
27 | #let dot(V,W) = re(mul(V,conj(W)))
28 |
29 | /// Calculates the squared normal of a complex number.
30 | /// - V (complex): The complex number.
31 | /// -> float
32 | #let normsq(V) = dot(V,V)
33 |
34 |
35 | /// Calculates the normal of a complex number
36 | /// - V (complex): The complex number.
37 | /// -> float
38 | #let norm(V) = calc.sqrt(normsq(V))
39 |
40 | /// Multiplies a complex number by a scale factor.
41 | /// - V (complex): The complex number to scale.
42 | /// - t (float): The scale factor.
43 | /// -> complex
44 | #let scale(V,t) = mul(V,(t,0))
45 |
46 | /// Returns a unit vector in the direction of a complex number.
47 | /// - V (complex): The complex number.
48 | /// -> vector
49 | #let unit(V) = scale(V, 1/norm(V))
50 |
51 | /// Inverts a complex number.
52 | /// - V (complex): The complex number
53 | /// -> complex
54 | #let inv(V) = scale(conj(V), 1/normsq(V))
55 |
56 | /// Divides two complex numbers.
57 | /// - V (complex): The complex number of the numerator.
58 | /// - W (complex): The complex number of the denominator.
59 | /// -> complex
60 | #let div(V,W) = mul(V,inv(W))
61 |
62 | /// Adds two complex numbers together.
63 | /// - V (complex): The complex number on the left hand side.
64 | /// - W (complex): The complex number on the right hand side.
65 | /// -> complex
66 | #let add(V,W) = (re(V) + re(W),im(V) + im(W))
67 |
68 | /// Subtracts two complex numbers together.
69 | /// - V (complex): The complex number on the left hand side.
70 | /// - W (complex): The complex number on the right hand side.
71 | /// -> complex
72 | #let sub(V,W) = (re(V) - re(W),im(V) - im(W))
73 |
74 | /// Calculates the argument of a complex number.
75 | /// - V (complex): The complex number.
76 | #let arg(V) = calc.atan2(..V) / 1rad
77 |
78 | /// Get the signed angle of two complex numbers from V to W.
79 | /// - V (complex): A complex number.
80 | /// - W (complex): A complex number.
81 | #let ang(V,W) = arg(div(W,V))
82 |
83 | // exp(i*a)
84 | #let expi(a) = (calc.cos(a),calc.sin(a))
85 |
86 | // Rotate by angle a
87 | #let rot(v,a) = mul(v,expi(a))
88 |
--------------------------------------------------------------------------------
/src/deps.typ:
--------------------------------------------------------------------------------
1 | #import "@preview/oxifmt:0.2.1"
2 |
--------------------------------------------------------------------------------
/src/draw.typ:
--------------------------------------------------------------------------------
1 | #import "draw/grouping.typ": intersections, group, scope, anchor, copy-anchors, set-ctx, get-ctx, for-each-anchor, on-layer, hide, floating
2 | #import "draw/transformations.typ": set-transform, rotate, translate, scale, set-origin, move-to, set-viewport
3 | #import "draw/styling.typ": set-style, fill, stroke, register-mark
4 | #import "draw/shapes.typ": circle, circle-through, arc, arc-through, mark, line, grid, content, rect, bezier, bezier-through, catmull, hobby, merge-path, polygon, multi-path
5 | #import "draw/projection.typ": ortho, on-xy, on-xz, on-yz
6 | #import "draw/util.typ": assert-version, register-coordinate-resolver
7 |
--------------------------------------------------------------------------------
/src/draw/styling.typ:
--------------------------------------------------------------------------------
1 | #import "/src/util.typ"
2 |
3 | /// Set current style
4 | ///
5 | /// - ..style (style): Style key-value pairs
6 | #let set-style(..style) = {
7 | assert.eq(
8 | style.pos().len(),
9 | 0,
10 | message: "set-style takes no positional arguments",
11 | )
12 |
13 | (ctx => {
14 | ctx.style = util.merge-dictionary(ctx.style, style.named())
15 |
16 | return (ctx: ctx)
17 | },)
18 | }
19 |
20 | /// Set current fill style
21 | ///
22 | /// Shorthand for `set-style(fill: )`
23 | ///
24 | /// - fill (paint): Fill style
25 | #let fill(fill) = set-style(fill: fill)
26 |
27 | /// Set current stroke style
28 | ///
29 | /// Shorthand for `set-style(stroke: )`
30 | ///
31 | /// - stroke (stroke): Stroke style
32 | #let stroke(stroke) = set-style(stroke: stroke)
33 |
34 | /// Register a custom mark to the canvas
35 | ///
36 | /// The mark should contain both anchors called **tip** and **base** that are used to determine the marks orientation. If unset both default to `(0, 0)`.
37 | /// An anchor named **center** is used as center of the mark, if present. Otherwise the mid between **tip** and **base** is used.
38 | ///
39 | /// ```typc example
40 | /// register-mark(":)", style => {
41 | /// circle((0,0), radius: .5, fill: yellow)
42 | /// arc((0,0), start: 180deg + 30deg, delta: 180deg - 60deg, anchor: "origin", radius: .3)
43 | /// circle((-0.15, 0.15), radius: .1, fill: white)
44 | /// circle((-0.10, 0.10), radius: .025, fill: black)
45 | /// circle(( 0.15, 0.15), radius: .1, fill: white)
46 | /// circle(( 0.20, 0.10), radius: .025, fill: black)
47 | ///
48 | /// anchor("tip", ( 0.5, 0))
49 | /// anchor("base", (-0.5, 0))
50 | /// })
51 | ///
52 | /// line((0,0), (3,0), mark: (end: ":)"))
53 | /// ```
54 | ///
55 | /// - symbol (str): Mark name
56 | /// - mnemonic (none,str): Mark short name
57 | /// - body (function): Mark drawing callback, receiving the mark style as argument and returning elements. Format `(styles) => elements`.
58 | #let register-mark(symbol, body, mnemonic: none) = {
59 | assert(type(symbol) == str)
60 | assert(type(body) == function)
61 |
62 | (ctx => {
63 | ctx.marks.marks.insert(symbol, body)
64 | if type(mnemonic) == str and mnemonic.len() > 0 {
65 | ctx.marks.mnemonics.insert(mnemonic, symbol)
66 | }
67 | return (ctx: ctx)
68 | },)
69 | }
70 |
--------------------------------------------------------------------------------
/src/draw/util.typ:
--------------------------------------------------------------------------------
1 | /// Assert that the cetz version of the canvas matches the given version (range).
2 | ///
3 | /// min (version): Minimum version (current >= min)
4 | /// max (none, version): First unsupported version (current < max)
5 | /// hint (string): Name of the function/module this assert is called from
6 | #let assert-version(min, max: none, hint: "") = {
7 | if hint != "" { hint = " by " + hint }
8 | (ctx => {
9 | /* Default to 2.0.0, as this is the first version that had elements as single functions. */
10 | let v = ctx.at("version", default: version(0,2,0))
11 | assert(min <= v,
12 | message: "CeTZ canvas version is " + str(v) + ", but the minimum required version" + hint + " is " + str(min))
13 | if max != none {
14 | assert(max > v,
15 | message: "CeTZ canvas version is " + str(v) + ", but the maximum supported version" + hint + " is " + str(min))
16 | }
17 |
18 | return (ctx: ctx)
19 | },)
20 | }
21 |
22 | /// Push a custom coordinate resolve function to the list of coordinate
23 | /// resolvers. This resolver is scoped to the current context scope!
24 | ///
25 | /// A coordinate resolver must be a function of the format `(context, coordinate) => coordinate`. And must _always_ return a valid coordinate or panic, in case of an error.
26 | ///
27 | /// If multiple resolvers are registered, coordinates get passed through all
28 | /// resolvers in reverse registering order. All coordinates get paased to cetz'
29 | /// default coordinate resolvers.
30 | ///
31 | /// ```typc example
32 | /// register-coordinate-resolver((ctx, c) => {
33 | /// if type(c) == dictionary and "log" in c {
34 | /// c = c.log.map(n => calc.log(n, base: 10))
35 | /// }
36 | /// return c
37 | /// })
38 | ///
39 | /// circle((log: (10, 0)), radius: .25)
40 | /// circle((log: (100, 0)), radius: .25)
41 | /// circle((log: (1000, 0)), radius: .25)
42 | /// ```
43 | ///
44 | /// - resolver (function): The resolver function, taking a context and a single coordinate and returning a single coordinate
45 | #let register-coordinate-resolver(resolver) = {
46 | assert.eq(type(resolver), function,
47 | message: "Coordinate resolver must be of type function (ctx, coordinate) => coordinate.")
48 |
49 | return (ctx => {
50 | if type(ctx.resolve-coordinate) == array {
51 | ctx.resolve-coordinate.push(resolver)
52 | } else {
53 | ctx.resolve-coordinate = (resolver,)
54 | }
55 |
56 | return (ctx: ctx)
57 | },)
58 | }
59 |
--------------------------------------------------------------------------------
/src/intersection.typ:
--------------------------------------------------------------------------------
1 | #import "vector.typ"
2 | #import "util.typ"
3 |
4 | /// Checks for a line-line intersection between the given points and returns its position, otherwise {{none}}.
5 | ///
6 | /// - a (vector): Line 1 point 1
7 | /// - b (vector): Line 1 point 2
8 | /// - c (vector): Line 2 point 1
9 | /// - d (vector): Line 2 point 2
10 | /// - ray (bool): When `true`, intersections will be found for the whole line instead of inbetween the given points.
11 | /// -> vector,none
12 | #let line-line(a, b, c, d, ray: false) = {
13 | let lli8(x1, y1, x2, y2, x3, y3, x4, y4) = {
14 | let nx = (x1*y2 - y1*x2)*(x3 - x4)-(x1 - x2)*(x3*y4 - y3*x4)
15 | let ny = (x1*y2 - y1*x2)*(y3 - y4)-(y1 - y2)*(x3*y4 - y3*x4)
16 | let d = (x1 - x2)*(y3 - y4)-(y1 - y2)*(x3 - x4)
17 | if d == 0 {
18 | return none
19 | }
20 | return (nx / d, ny / d, 0)
21 | }
22 | let pt = lli8(a.at(0), a.at(1), b.at(0), b.at(1),
23 | c.at(0), c.at(1), d.at(0), d.at(1))
24 | if pt != none {
25 | let on-line(pt, a, b) = {
26 | let (x, y, ..) = pt
27 | let epsilon = util.float-epsilon
28 | let mx = calc.min(a.at(0), b.at(0)) - epsilon
29 | let my = calc.min(a.at(1), b.at(1)) - epsilon
30 | let Mx = calc.max(a.at(0), b.at(0)) + epsilon
31 | let My = calc.max(a.at(1), b.at(1)) + epsilon
32 | return mx <= x and Mx >= x and my <= y and My >= y
33 | }
34 | if ray or (on-line(pt, a, b) and on-line(pt, c, d)) {
35 | return pt
36 | }
37 | }
38 | }
39 |
40 | /// Finds the intersections of a line and cubic bezier.
41 | ///
42 | /// - s (vector): Bezier start point
43 | /// - e (vector): Bezier end point
44 | /// - c1 (vector): Bezier control point 1
45 | /// - c2 (vector): Bezier control point 2
46 | /// - la (vector): Line start point
47 | /// - lb (vector): Line end point
48 | /// - ray (bool): When `true`, intersections will be found for the whole line instead of inbetween the given points.
49 | /// -> array
50 | #let line-cubic(la, lb, s, e, c1, c2) = {
51 | import "/src/bezier.typ": line-cubic-intersections as line-cubic
52 | return line-cubic(la, lb, s, e, c1, c2)
53 | }
54 |
55 | /// Finds the intersections of a line and path in 2D. The path should be given as a {{drawable}} of type `path`.
56 | ///
57 | /// - la (vector): Line start
58 | /// - lb (vector): Line end
59 | /// - path (drawable): The path.
60 | /// -> array
61 | #let line-path(la, lb, path) = {
62 | let pts = ()
63 |
64 | for ((start, closed, segments)) in path.at("segments", default: ()) {
65 | let origin = start
66 | for ((kind, ..args)) in segments {
67 | if kind == "l" {
68 | let pt = line-line(la, lb, origin, args.last())
69 | if pt != none {
70 | pts.push(pt)
71 | }
72 | } else if kind == "c" {
73 | let (c1, c2, e) = args
74 | pts += line-cubic(la, lb, origin, e, c1, c2)
75 | }
76 |
77 | origin = args.last()
78 | }
79 |
80 | if closed {
81 | let pt = line-line(la, lb, origin, start)
82 | if pt != none {
83 | pts.push(pt)
84 | }
85 | }
86 | }
87 |
88 | return pts
89 | }
90 |
91 | /// Finds the intersections between two path {{drawable}}s in 2D.
92 | ///
93 | /// - a (path): Path a
94 | /// - b (path): Path b
95 | /// - samples (int): Number of samples to use for bezier curves
96 | /// -> array
97 | #let path-path(a, b, samples: 8) = {
98 | import "bezier.typ": cubic-point
99 |
100 | let pts = ()
101 |
102 | for ((start, closed, segments)) in a.at("segments", default: ()) {
103 | let origin = start
104 | for ((kind, ..args)) in segments {
105 | if kind == "l" {
106 | pts += line-path(origin, args.last(), b)
107 | } else if kind == "c" {
108 | let (c1, c2, e) = args
109 | let line-strip = range(samples + 1).map(t => {
110 | cubic-point(origin, e, c1, c2, t / samples)
111 | })
112 |
113 | for i in range(1, line-strip.len()) {
114 | pts += line-path(line-strip.at(i - 1), line-strip.at(i), b)
115 | }
116 | }
117 |
118 | origin = args.last()
119 | }
120 |
121 | if closed {
122 | pts += line-path(origin, start, b)
123 | }
124 | }
125 | return pts
126 | }
127 |
--------------------------------------------------------------------------------
/src/lib.typ:
--------------------------------------------------------------------------------
1 | #import "version.typ": version
2 |
3 | #import "canvas.typ": canvas
4 | #import "draw.typ"
5 |
6 | // Expose utilities
7 | #import "vector.typ"
8 | #import "matrix.typ"
9 | #import "styles.typ"
10 | #import "coordinate.typ"
11 | #import "intersection.typ"
12 | #import "drawable.typ"
13 | #import "process.typ"
14 | #import "util.typ"
15 | #import "path-util.typ"
16 | #import "mark.typ"
17 | #import "mark-shapes.typ"
18 | #import "sorting.typ"
19 |
20 | // Libraries
21 | #import "lib/palette.typ"
22 | #import "lib/angle.typ"
23 | #import "lib/tree.typ"
24 | #import "lib/decorations.typ"
25 |
--------------------------------------------------------------------------------
/src/lib/decorations.typ:
--------------------------------------------------------------------------------
1 | #import "decorations/brace.typ": brace, brace-default-style, flat-brace, flat-brace-default-style
2 | #import "decorations/path.typ": zigzag, wave, coil, square
3 |
--------------------------------------------------------------------------------
/src/lib/palette.typ:
--------------------------------------------------------------------------------
1 | #let base-style = (stroke: (paint: black), fill: none)
2 |
3 | /// Create a new palette based on a base style
4 | ///
5 | /// ```typc example
6 | /// let p = cetz.palette.new(colors: (red, blue, green))
7 | /// for i in range(0, p("len")) {
8 | /// set-style(..p(i))
9 | /// circle((0,0), radius: .5)
10 | /// set-origin((1.1, 0))
11 | /// }
12 | /// ```
13 | ///
14 | /// The functions returned by this function have the following named arguments:
15 | /// - fill (bool) = true: If true, the returned fill color is one of the colors from the `colors` list, otherwise the base styles fill is used.
16 | /// - stroke (bool) = false: If true, the returned stroke color is one of the colors from the `colors` list, otherwise the base styles stroke color is used.
17 | ///
18 | /// You can use a palette for stroking via: `red.with(stroke: true)`.
19 | ///
20 | /// - base (style): Style dictionary to use as base style for the styles generated per color
21 | /// - colors (none, array): List of colors the returned palette should return styles with.
22 | /// - dash (none, array): List of stroke dash patterns the returned palette should return styles with.
23 | /// -> function
24 | #let new(base: base-style, colors: (), dash: ()) = {
25 | if not "stroke" in base { base.stroke = (paint: black, thickness: 1pt, dash: "solid") }
26 | if not "fill" in base { base.fill = none }
27 |
28 | let color-n = colors.len()
29 | let pattern-n = dash.len()
30 | return (index, fill: true, stroke: false) => {
31 | if index == "len" { return calc.max(color-n, pattern-n, 1) }
32 |
33 | let style = base
34 | if pattern-n > 0 {
35 | style.stroke.dash = dash.at(calc.rem(index, pattern-n))
36 | }
37 | if color-n > 0 {
38 | if stroke {
39 | style.stroke.paint = colors.at(calc.rem(index, color-n))
40 | }
41 | if fill {
42 | style.fill = colors.at(calc.rem(index, color-n))
43 | }
44 | }
45 | return style
46 | }
47 | }
48 |
49 | // Predefined color themes
50 | #let tango-colors = (
51 | "edd400", "f57900", "c17d11",
52 | "73d216", "3465a4", "75507b",
53 | "cc0000", "d3d7cf", "555753").map(rgb)
54 | #let tango-light-colors = (
55 | "fce94f", "fcaf3e", "e9b96e",
56 | "8ae234", "729fcf", "ad7fa8",
57 | "ef2929", "eeeeec", "888a85").map(rgb)
58 | #let tango-dark-colors = (
59 | "c4a000", "ce5c00", "8f5902",
60 | "4e9a06", "204a87", "5c3566",
61 | "a40000", "babdb6", "2e3436").map(rgb)
62 | #let rainbow-colors = (
63 | "#9400D4", "#4B0082", "#0000FF",
64 | "#00FF00", "#FFFF00", "#FF7F00",
65 | "#FF0000").map(rgb)
66 |
67 | #let red-colors = (
68 | "#FFCCCC", "#FF9999", "#FF6666",
69 | "#FF3333", "#CC0000").map(rgb)
70 | #let orange-colors = (
71 | "#FFE5CC", "#FFCC99", "#FFB266",
72 | "#FF9933", "#FF8000").map(rgb)
73 | #let light-green-colors = (
74 | "#E5FFCC", "#CCFF99", "#B2FF66",
75 | "#99FF33", "#72E300", "#66CC00",
76 | "#55A800", "#478F00", "#3A7300",
77 | "#326300").map(rgb)
78 | #let dark-green-colors = (
79 | "#80E874", "#5DD45D", "#3CC23C",
80 | "#009900", "#006E00").map(rgb)
81 | #let turquoise-colors = (
82 | "#C0FFD3", "#99FFCC", "#66FFB2",
83 | "#33FF99", "#4BD691").map(rgb)
84 | #let cyan-colors = (
85 | "#CCFFFF", "#99FFFF", "#66FFFF",
86 | "#00F3F3", "#00DADA").map(rgb)
87 | #let blue-colors = (
88 | "#BABAFF", "#9999FF", "#6666FF",
89 | "#3333FF", "#0000CC").map(rgb)
90 | #let indigo-colors = (
91 | "#BABAFF", "#9999FF", "#6666FF",
92 | "#3333FF", "#0000CC").map(rgb)
93 | #let purple-colors = (
94 | "#E0C2FF", "#CC99FF", "#B266FF",
95 | "#9933FF", "#7F00FF").map(rgb)
96 | #let magenta-colors = (
97 | "#FFD4FF", "#FF99FF", "#FF66FF",
98 | "#F331F3", "#DA00DA").map(rgb)
99 | #let pink-colors = (
100 | "#FFCCE5", "#FF99CC", "#FF66B2",
101 | "#FF3399", "#F20C7F", "#DB006B",
102 | "#C30061", "#99004C", "#800040",
103 | "#660033").map(rgb)
104 |
105 |
106 | // Predefined palettes
107 | #let gray = new(colors: range(90, 40, step: -12).map(v => luma(v * 1%)))
108 |
109 | #let red = new(colors: red-colors)
110 | #let orange = new(colors: orange-colors)
111 | #let light-green = new(colors: light-green-colors)
112 | #let dark-green = new(colors: dark-green-colors)
113 | #let turquoise = new(colors: turquoise-colors)
114 | #let cyan = new(colors: cyan-colors)
115 | #let blue = new(colors: blue-colors)
116 | #let indigo = new(colors: indigo-colors)
117 | #let purple = new(colors: purple-colors)
118 | #let magenta = new(colors: magenta-colors)
119 | #let pink = new(colors: pink-colors)
120 |
121 | #let rainbow = new(colors: rainbow-colors)
122 |
123 | #let tango = new(colors: tango-colors)
124 | #let tango-light = new(colors: tango-light-colors)
125 | #let tango-dark = new(colors: tango-dark-colors)
126 |
--------------------------------------------------------------------------------
/src/polygon.typ:
--------------------------------------------------------------------------------
1 | #import "/src/vector.typ"
2 |
3 | /// Returns a list of polygon points from
4 | /// a list of segments.
5 | ///
6 | /// Cubic segments get linearized by sampling.
7 | ///
8 | /// - segment (array): List of segments
9 | /// - samples (int): Number of samples
10 | /// -> array
11 | #let from-subpath(subpath, samples: 10) = {
12 | import "/src/bezier.typ": cubic-point
13 | let (origin, _, segments) = subpath
14 |
15 | let poly = (origin,)
16 | for ((kind, ..args)) in segments {
17 | if kind == "c" {
18 | let (c1, c2, e) = args
19 | poly += range(0, samples).map(t => {
20 | cubic-point(poly.last(), e, c1, c2, t / (samples - 1))
21 | })
22 | } else {
23 | poly += args
24 | }
25 | }
26 | return poly
27 | }
28 |
29 | /// Computes the signed area of a 2D polygon.
30 | ///
31 | /// The formula used is the following:
32 | /// $ 1/2 \sum_{i}=0^{n-1} x_i*y_i+1 - x_i+1*y_i $
33 | ///
34 | /// - points (array): List of Vectors of dimension >= 2
35 | /// -> float
36 | #let signed-area(points) = {
37 | let a = 0
38 | let n = points.len()
39 | let (cx, cy) = (0, 0)
40 | for i in range(0, n) {
41 | let (x0, y0, ..) = points.at(i)
42 | let (x1, y1, ..) = points.at(calc.rem(i + 1, n))
43 | cx += (x0 + x1) * (x0 * y1 - x1 * y0)
44 | cy += (y0 + y1) * (x0 * y1 - x1 * y0)
45 | a += x0 * y1 - x1 * y0
46 | }
47 | return .5 * a
48 | }
49 |
50 | /// Returns the winding order of a 2D polygon
51 | /// by using it's signed area.
52 | ///
53 | /// Returns either "ccw" (counter clock-wise) or "cw" (clock-wise) or none.
54 | ///
55 | /// - point (array): List of polygon points
56 | /// -> str,none
57 | #let winding-order(points) = {
58 | let area = signed-area(points)
59 | if area > 0 {
60 | "cw"
61 | } else if area < 0 {
62 | "ccw"
63 | } else {
64 | none
65 | }
66 | }
67 |
68 | // Calculate triangle centroid
69 | #let triangle-centroid(points) = {
70 | assert.eq(points.len(), 3)
71 |
72 | let (mx, my, mz) = (0, 0, 0)
73 | for p in points {
74 | let (x, y, z) = p
75 | mx += x
76 | my += y
77 | mz += z
78 | }
79 | return (mx / 3, my / 3, mz / 3)
80 | }
81 |
82 | // Calculate the centroid of a line, triangle or simple polygon
83 | // Formulas:
84 | // https://en.wikipedia.org/wiki/Centroid
85 | #let simple-centroid(points) = {
86 | return if points.len() <= 1 {
87 | none
88 | } else if points.len() == 2 {
89 | vector.lerp(..points, .5)
90 | } else if points.len() == 3 {
91 | triangle-centroid(points)
92 | } else if points.len() >= 3 {
93 | // Skip polygons with multiple z values
94 | let z = points.first().at(2, default: 0)
95 | if points.any(p => p.at(2) != z) {
96 | return none
97 | }
98 |
99 | let a = 0
100 | let n = points.len()
101 | let (cx, cy) = (0, 0)
102 | for i in range(0, n) {
103 | let (x0, y0, ..) = points.at(i)
104 | let (x1, y1, ..) = points.at(calc.rem(i + 1, n))
105 | cx += (x0 + x1) * (x0 * y1 - x1 * y0)
106 | cy += (y0 + y1) * (x0 * y1 - x1 * y0)
107 | a += x0 * y1 - x1 * y0
108 | }
109 | return (cx/(3*a), cy/(3*a), z)
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/src/process.typ:
--------------------------------------------------------------------------------
1 | #import "util.typ"
2 | #import "path-util.typ"
3 | #import "aabb.typ"
4 | #import "drawable.typ"
5 | #import "vector.typ"
6 |
7 |
8 | /// Processes an element's function to get its drawables and bounds. Returns a {{dictionary}} with the key-values: `ctx` The modified context object, `bounds` The {{aabb}} of the element's drawables, `drawables` An {{array}} of the element's {{drawable}}s.
9 | ///
10 | /// - ctx (ctx): The current context object.
11 | /// - element-func (function): A function that when passed {{ctx}}, it should return an element dictionary.
12 | #let element(ctx, element-func) = {
13 | let bounds = none
14 | let element
15 | let anchors = (:)
16 |
17 | (ctx, ..element,) = element-func(ctx)
18 | if "drawables" in element {
19 | if type(element.drawables) == dictionary {
20 | element.drawables = (element.drawables,)
21 | }
22 | for drawable in element.drawables {
23 | if drawable.bounds {
24 | bounds = aabb.aabb(
25 | if drawable.type == "path" {
26 | path-util.bounds(drawable.segments)
27 | } else if drawable.type == "content" {
28 | let (x, y, _, w, h,) = drawable.pos + (drawable.width, drawable.height)
29 | ((x + w / 2, y - h / 2, 0.0), (x - w / 2, y + h / 2, 0.0))
30 | },
31 | init: bounds
32 | )
33 | }
34 | }
35 | }
36 |
37 | let name = element.at("name", default: none)
38 | if name != none {
39 | assert.eq(type(name), str,
40 | message: "Element name must be a string")
41 | assert(not name.contains("."),
42 | message: "Invalid name for element '" + element.name + "'; name must not contain '.'")
43 |
44 | if "anchors" in element {
45 | ctx.nodes.insert(name, element)
46 | if ctx.groups.len() > 0 {
47 | ctx.groups.last().push(name)
48 | }
49 | }
50 | }
51 |
52 | if ctx.debug and bounds != none {
53 | element.drawables.push(drawable.path(
54 | ((bounds.low, true, (
55 | ("l", (bounds.high.at(0), bounds.low.at(1), 0)),
56 | ("l", bounds.high),
57 | ("l", (bounds.low.at(0), bounds.high.at(1), 0)))),),
58 | stroke: red,
59 | close: true
60 | ))
61 | }
62 |
63 | return (
64 | ctx: ctx,
65 | bounds: bounds,
66 | drawables: element.at("drawables", default: ()),
67 | )
68 | }
69 |
70 | /// Runs the `element` function for a list of element functions and aggregates the results.
71 | /// - ctx (ctx): The current context object.
72 | /// - body (array): The array of element functions to process.
73 | /// -> dictionary
74 | #let many(ctx, body) = {
75 | let drawables = ()
76 | let bounds = none
77 |
78 | for el in body {
79 | let r = element(ctx, el)
80 | if r != none {
81 | if r.bounds != none {
82 | let pts = (r.bounds.low, r.bounds.high,)
83 | bounds = aabb.aabb(pts, init: bounds)
84 | }
85 | ctx = r.ctx
86 | drawables += r.drawables
87 | }
88 | }
89 | return (ctx: ctx, bounds: bounds, drawables: drawables)
90 | }
91 |
--------------------------------------------------------------------------------
/src/sorting.typ:
--------------------------------------------------------------------------------
1 | #import "/src/vector.typ"
2 | #import "/src/util.typ"
3 |
4 | /// Sort list of points by distance to a
5 | /// reference point.
6 | ///
7 | /// - points (array): List of points to sort
8 | /// - reference (vec): Reference point
9 | /// -> List of points
10 | #let points-by-distance(ctx, points, reference: (0, 0, 0)) = {
11 | let reference = util.apply-transform(ctx.transform, reference)
12 | return points.sorted(key: pt => {
13 | vector.dist(pt, reference)
14 | })
15 | }
16 |
17 | /// Sort list of 2D points by angle to a
18 | /// reference 2D point in CCW order.
19 | /// Z component is ignored.
20 | ///
21 | /// - points (array): List of points to sort
22 | /// - reference (vec): Reference point
23 | /// -> List of points
24 | #let points-by-angle(ctx, points, reference: (0, 0, 0)) = {
25 | let (rx, ry, ..) = util.apply-transform(ctx.transform, reference)
26 | return points.sorted(key: ((px, py, ..)) => {
27 | 360deg - calc.atan2(rx - px, ry - py)
28 | })
29 | }
30 |
--------------------------------------------------------------------------------
/src/version.typ:
--------------------------------------------------------------------------------
1 | #let version = version(0,3,4)
2 |
--------------------------------------------------------------------------------
/tests/.gitignore:
--------------------------------------------------------------------------------
1 | **/out/*
2 | **/diff/*
3 | *.pdf
4 |
--------------------------------------------------------------------------------
/tests/anchor-centroid/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/anchor-centroid/ref/1.png
--------------------------------------------------------------------------------
/tests/anchor-centroid/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let x(pos) = {
6 | import draw: *
7 | group({
8 | set-origin(pos)
9 | scale(.1)
10 | stroke(red)
11 | line((-1, -1), (1, 1))
12 | line((-1, 1), (1, -1))
13 | })
14 | }
15 |
16 | #test-case({
17 | import draw: *
18 |
19 | line((-1, -1), (1, 1), name: "elem", close: true)
20 | x("elem.centroid")
21 | })
22 |
23 | #test-case({
24 | import draw: *
25 |
26 | line((-1, -1), (+1, -1), (0, 1), name: "elem", close: true)
27 | x("elem.centroid")
28 | })
29 |
30 | #test-case({
31 | import draw: *
32 |
33 | line((-1, -1), (+1, -1), (+1, +1), (-1, +1), name: "elem", close: true)
34 | x("elem.centroid")
35 | })
36 |
37 | #test-case({
38 | import draw: *
39 |
40 | line((-1, -1), (+1, -1), (+1, +0), (+0, +0),
41 | (+0, +1), (-1, +1), name: "elem", close: true)
42 | x("elem.centroid")
43 | })
44 |
45 | #test-case({
46 | import draw: *
47 |
48 | merge-path(name: "elem", close: true, {
49 | arc((0,0), start: 0deg, stop: 90deg)
50 | line((), (rel: (-1, 0)), (rel: (0, -1)))
51 | })
52 | x("elem.centroid")
53 | })
54 |
55 | #test-case({
56 | import draw: *
57 |
58 | merge-path(name: "elem", close: true, {
59 | // Circle is in merge-path!
60 | circle(())
61 | })
62 | x("elem.centroid")
63 | })
64 |
--------------------------------------------------------------------------------
/tests/angle/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/angle/ref/1.png
--------------------------------------------------------------------------------
/tests/angle/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let angles = range(0, 360, step: 36).map(v => v * 1deg)
6 |
7 | #test-case(a => {
8 | import draw: *
9 | import angle: angle
10 |
11 | let (o, a, b) = ((0,0), (1,0), (calc.cos(a), calc.sin(a)))
12 | line(a, o, b)
13 | angle(o, a, b, label: $alpha$)
14 | }, args: angles)
15 |
16 | #test-case(a => {
17 | import draw: *
18 | import angle: angle
19 |
20 | let (o, a, b) = ((0,0), (1,0), (calc.cos(a), calc.sin(a)))
21 | line(a, o, b)
22 | angle(o, a, b, label: $alpha$, direction: "cw")
23 | }, args: angles)
24 |
25 | #test-case(a => {
26 | import draw: *
27 | import angle: angle
28 |
29 | let (o, a, b) = (
30 | (0, 0),
31 | (calc.cos(a+90deg), calc.sin(a+90deg)), (calc.cos(a), calc.sin(a))
32 | )
33 |
34 | line(a, o, b)
35 | angle(o, a, b, label: $alpha$, direction: "cw")
36 | }, args: angles)
37 |
38 | #test-case(a => {
39 | import draw: *
40 | import angle: angle
41 |
42 | let (o, a, b) = (
43 | (0, 0),
44 | (calc.cos(a+90deg), calc.sin(a+90deg)), (calc.cos(a), calc.sin(a))
45 | )
46 |
47 | line(a, o, b)
48 | angle(o, a, b, label: $alpha$, direction: "ccw")
49 | }, args: angles)
50 |
51 |
52 | #test-case({
53 | import draw: *
54 | import angle: angle
55 |
56 | let (a, b, c) = ((-1, 1), (0, 0), (1, 2))
57 |
58 | line(a, b, c)
59 | set-style(angle: (stroke: red, label-radius: 1))
60 | angle(b, c, a, mark: (start: ">", end: ">"), label: $omega$)
61 |
62 | translate((2,0,0))
63 |
64 | line(a, b, c)
65 | set-style(stroke: blue)
66 | set-style(angle: (stroke: auto, radius: 1, label-radius: .5))
67 | angle(b, c, a, mark: (start: "|", end: ">"),
68 | direction: "cw", label: $alpha$, name: "alpha")
69 |
70 | set-style(stroke: black)
71 | circle("alpha.origin", radius: .15)
72 | circle("alpha.label", radius: .25)
73 | circle("alpha.start", radius: .25)
74 | circle("alpha.end", radius: .25)
75 | })
76 |
77 | #test-case({
78 | import draw: *
79 | import angle: *
80 |
81 | angle((0,0), (1,0), (0,1), mark: (end: ">"))
82 | })
83 |
84 | #test-case({
85 | import draw: *
86 | import angle: *
87 |
88 | angle((0,0), (1,0), (0,1), mark: (end: ">"), direction: "cw")
89 | })
90 |
91 | #test-case({
92 | import draw: *
93 | import angle: *
94 |
95 | angle((0,0), (1,0), (0,1), radius: .5cm)
96 | angle((0,0), (1,0), (0,1), radius: 75%, stroke: blue)
97 | angle((0,0), (1,0), (0,1), radius: 1, stroke: green)
98 | })
99 |
--------------------------------------------------------------------------------
/tests/arc-previous-position/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/arc-previous-position/ref/1.png
--------------------------------------------------------------------------------
/tests/arc-previous-position/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | arc((0,0), start: 0deg, stop: 180deg)
8 | circle((), radius: .1, fill: blue)
9 | }))
10 |
11 | #box(stroke: 2pt + red, canvas({
12 | import draw: *
13 |
14 | arc((0,0), start: 180deg, stop: 0deg)
15 | circle((), radius: .1, fill: blue)
16 | }))
17 |
18 | #box(stroke: 2pt + red, canvas({
19 | import draw: *
20 |
21 | arc((0,0), start: 180deg, stop: 0deg, update-position: false)
22 | circle((), radius: .1, fill: blue)
23 | }))
24 |
--------------------------------------------------------------------------------
/tests/arc-through/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/arc-through/ref/1.png
--------------------------------------------------------------------------------
/tests/arc-through/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let show-points(..pts) = {
5 | import draw: *
6 | for pt in pts.pos() {
7 | circle(pt, radius: .1)
8 | }
9 | }
10 |
11 | #let test(a, b, c) = {
12 | import draw: *
13 | group({
14 | anchor("default", (0,0,0))
15 | show-points(a, b, c)
16 | arc-through(a, b, c)
17 | }, name: "g", anchor: "west", padding: .1)
18 | set-origin("g.east")
19 | }
20 |
21 | #box(stroke: 2pt + red, canvas(length: 1cm, {
22 | import draw: *
23 |
24 | test((0,0), (1, 1), (2, 0))
25 | test((0,0), (1,-1), (2, 0))
26 | test((0,1), (1, 0), (0,-1))
27 | test((0,1), (-1,0), (0,-1))
28 | }))
29 |
30 | #box(stroke: 2pt + red, canvas(length: 1cm, {
31 | import draw: *
32 |
33 | for a in range(36, 360 + 36, step: 36) {
34 | let a = a * 1deg
35 | test((1,0),
36 | (calc.cos(a / 2), calc.sin(a / 2)),
37 | (calc.cos(a), calc.sin(a)))
38 | }
39 | }))
40 |
41 | #box(stroke: 2pt + red, canvas(length: 1cm, {
42 | import draw: *
43 |
44 | for d in range(0, 8 + 1) {
45 | let d = (d - 2) / 5
46 | test((0,0), (1,d), (2,.5))
47 | }
48 | }))
49 |
50 | #box(stroke: 2pt + red, canvas(length: 1cm, {
51 | import draw: *
52 |
53 | // The style radius must not influence the
54 | // arc radius!
55 | set-style(radius: 5)
56 | set-style(arc: (radius: 5))
57 | test((0,0), (1, 1), (2, 0))
58 | }))
59 |
60 | #box(stroke: 2pt + red, canvas(length: 1cm, {
61 | import draw: *
62 |
63 | arc-through((0,0), (1,1), (2,0))
64 | arc-through((0,0,1), (1,1,1), (2,0,1), stroke: blue)
65 | }))
66 |
--------------------------------------------------------------------------------
/tests/arc/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/arc/ref.png
--------------------------------------------------------------------------------
/tests/arc/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/arc/ref/1.png
--------------------------------------------------------------------------------
/tests/arc/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas(length: 1cm, {
5 | import draw: *
6 |
7 | for r in ((1,1), (0.5,1), (1,0.5)) {
8 | translate((2.5, 0, 0))
9 | group({
10 | for a in range(0, 360 + 45, step: 45) {
11 | if a == 0 {
12 | a = 1
13 | }
14 | a *= 1deg
15 | circle((0,0), radius: r, stroke: red)
16 | arc((0,0), start: 45deg, delta: a, radius: r, name: "a",
17 | anchor: "origin", mode: "PIE", fill: blue)
18 |
19 | circle("a.arc-start", fill: green, radius: .1)
20 | circle("a.arc-end", fill: red, radius: .1)
21 | translate((0, 2.5, 0))
22 | }
23 | })
24 | }
25 | }))
26 |
27 | #box(stroke: 2pt + red, canvas(length: 1cm, {
28 | import draw: *
29 |
30 | arc((0,0), start: 45deg, delta: 90deg)
31 | arc((0,0,1), start: 45deg, delta: 90deg, stroke: blue)
32 | }))
33 |
--------------------------------------------------------------------------------
/tests/arrows/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/arrows/ref/1.png
--------------------------------------------------------------------------------
/tests/arrows/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 |
8 | let next(mark) = {
9 | line((), (rel: (1, 0)), mark: mark)
10 | move-to((rel: (-1, .25)))
11 | }
12 |
13 | set-style(fill: blue, mark: (fill: auto))
14 | rotate(90deg)
15 |
16 | let marks = (">", "<", "|", "<>", "o")
17 | for m in marks {
18 | next((end: m))
19 | }
20 |
21 | for m in marks {
22 | next((start: m))
23 | }
24 |
25 | fill(none)
26 |
27 | let marks = (">", "<")
28 | for m in marks {
29 | next((end: m))
30 | }
31 |
32 | for m in marks {
33 | next((start: m))
34 | }
35 | } )
36 |
37 | #test-case({
38 | import draw: *
39 |
40 | line((0,0), (9,0), stroke: blue + 1pt)
41 | line((0,0), (9,0), stroke: green + .1pt)
42 | line((0,-1), (9,-1), stroke: blue + 1pt)
43 | line((0,-1), (9,-1), stroke: green + .1pt)
44 |
45 | set-style(mark: (stroke: (paint: green, miter-limit: 50),
46 | fill: red))
47 |
48 | for x in range(0, 18) {
49 | line((x * .5, -1), (x * .5, 0), mark: (start: ">", end: ">",
50 | width: (x / 50 + .05)))
51 | }
52 | })
53 |
54 | #test-case({
55 | import draw: *
56 |
57 | line((0,0), (9,0), stroke: blue + 1pt)
58 | line((0,0), (9,0), stroke: green + .1pt)
59 | line((0,-1), (9,-1), stroke: blue + 1pt)
60 | line((0,-1), (9,-1), stroke: green + .1pt)
61 |
62 | set-style(mark: (stroke: (paint: green, miter-limit: 50),
63 | fill: red))
64 |
65 | for x in range(0, 18) {
66 | line((x * .5, -1), (x * .5, 0), mark: (start: "<", end: "<",
67 | width: (x / 50 + .05)))
68 | }
69 | })
70 |
71 | #test-case({
72 | import draw: *
73 |
74 | line((0,0), (9,0), stroke: blue + 1pt)
75 | line((0,0), (9,0), stroke: green + .1pt)
76 | line((0,-1), (9,-1), stroke: blue + 1pt)
77 | line((0,-1), (9,-1), stroke: green + .1pt)
78 |
79 | set-style(mark: (stroke: (paint: green, miter-limit: 50, join: "round"),
80 | fill: red))
81 |
82 | for x in range(0, 18) {
83 | line((x * .5, -1), (x * .5, 0), mark: (start: "<", end: ">",
84 | width: (x / 50 + .05)))
85 | }
86 | })
87 |
88 | #test-case({
89 | import draw: *
90 |
91 | line((0,0), (9,0), stroke: blue + 1pt)
92 | line((0,0), (9,0), stroke: green + .1pt)
93 | line((0,-1), (9,-1), stroke: blue + 1pt)
94 | line((0,-1), (9,-1), stroke: green + .1pt)
95 |
96 | set-style(mark: (stroke: (paint: green, miter-limit: 50, join: "bevel"),
97 | fill: red))
98 |
99 | for x in range(0, 18) {
100 | line((x * .5, -1), (x * .5, 0), mark: (start: "<", end: ">",
101 | width: (x / 50 + .05)))
102 | }
103 | })
104 |
105 | // Issue #830
106 | #test-case({
107 | import draw: *
108 | line((0, 0), (1, 0), mark: (start: "stealth"))
109 | line((0, -1), (1, -1), mark: (end: "stealth"))
110 | line((0, -2), (1, -2), mark: (start: "stealth", end: "stealth"))
111 | line((0, -3), (1, -3), mark: (symbol: "stealth",))
112 | })
113 |
--------------------------------------------------------------------------------
/tests/bezier-shortening/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/bezier-shortening/ref/1.png
--------------------------------------------------------------------------------
/tests/bezier-shortening/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/src/bezier.typ": cubic-shorten, cubic-point, cubic-arclen
4 |
5 | #let test(d, curve: ((0,0), (3,0), (1,2), (2,-8))) = {
6 | import draw: *
7 |
8 | bezier(..curve, name: "o", stroke: 3pt + blue)
9 |
10 | let short = cubic-shorten(..curve, d, samples: 505)
11 | bezier(..short, stroke: 3pt + black, name: "s")
12 |
13 | let o-len = cubic-arclen(..curve)
14 | let s-len = cubic-arclen(..short)
15 | content((4,0), [#calc.round(o-len - s-len, digits: 2)])
16 | }
17 |
18 | #for d in (0, .1, .25, .5, 1, 2, 3) {
19 | block(stroke: 2pt + red, canvas(length: .5cm, {
20 | test(-d)
21 | }))
22 | block(stroke: 2pt + red, canvas(length: .5cm, {
23 | test(+d)
24 | }))
25 | }
26 |
--------------------------------------------------------------------------------
/tests/bezier-through/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/bezier-through/ref/1.png
--------------------------------------------------------------------------------
/tests/bezier-through/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let bezier-through(a, b, c, ..args) = {
6 | import cetz.draw: *
7 | line(a, b, c, stroke: gray)
8 | for pt in (a, b, c) {
9 | circle(pt, radius: .1cm, fill: gray, stroke: none)
10 | }
11 |
12 | cetz.draw.bezier-through(a, b, c, ..args)
13 | }
14 |
15 | #test-case(points => {
16 | bezier-through(..points)
17 | }, args: (
18 | ((0,0), (0, 0), (2,0)),
19 | ((0,0), (2, 0), (2,0)),
20 | ((0,0), (1, 0), (2,0)),
21 | ((0,0), (1, 1), (2,0)),
22 | ((0,0), (1,-1), (2,0)),
23 | ((0,0), (1, 1), (2,2)),
24 | ((0,0), (1, 2), (2,2)),
25 | ((0,0), (1, 0), (2,2)),
26 | ((0,0), (3, 0), (1,0)),
27 | ((0,0), (-3,0), (1,0)),
28 | ))
29 |
30 | #test-case({
31 | import draw: *
32 |
33 | merge-path(close: true, {
34 | bezier-through((-1, 0), (-calc.cos(45deg), calc.sin(45deg)), (0, 1))
35 | bezier-through((0, 1), (calc.cos(45deg), calc.sin(45deg)), (1, 0))
36 | bezier-through((1, 0), (calc.cos(45deg), -calc.sin(45deg)), (0, -1))
37 | bezier-through((0, -1), (-calc.cos(45deg), -calc.sin(45deg)), (-1, 0))
38 | })
39 | })
40 |
--------------------------------------------------------------------------------
/tests/bezier/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/bezier/ref/1.png
--------------------------------------------------------------------------------
/tests/bezier/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | /* Make sure the current position is set to the curves end point [236] */
5 | #block(stroke: 2pt + red, canvas(length: .5cm, {
6 | import draw: *
7 |
8 | set-style(radius: .1)
9 | circle((), fill: green)
10 | bezier((0,0), (3, 0), (1,1), (2,-1))
11 | circle((), fill: red)
12 | }))
13 |
--------------------------------------------------------------------------------
/tests/bounds/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/bounds/ref/1.png
--------------------------------------------------------------------------------
/tests/bounds/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | group(name: "g", {
8 | scale(.25)
9 | rotate(-37deg)
10 | bezier((0,0), (0, 10), (1,-10), (-5,20))
11 | })
12 | on-layer(-1, {
13 | rect("g.south-west", "g.north-east", stroke: .5pt + green)
14 | })
15 | }))
16 |
17 | #box(stroke: 2pt + red, canvas({
18 | import draw: *
19 |
20 | group(name: "g", {
21 | arc((0,0), start: 45deg, stop: 360deg - 45deg)
22 | })
23 | on-layer(-1, {
24 | rect("g.south-west", "g.north-east", stroke: .5pt + green)
25 | })
26 | }))
27 |
28 | #box(stroke: 2pt + red, canvas({
29 | import draw: *
30 |
31 | let pts = ((-1.414213562373095, 0),
32 | (-1.4142135623730954, -1.414213562373095),
33 | (-1.8047378541243648, -0.3905242917512698),
34 | (-1.8047378541243653, -1.023689270621825))
35 | group(name: "g", {
36 | bezier(..pts)
37 | })
38 |
39 | on-layer(-1, {
40 | rect("g.south-west", "g.north-east", stroke: .5pt + green)
41 | })
42 | }))
43 |
--------------------------------------------------------------------------------
/tests/canvas-baseline/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | This is an example #canvas(baseline: "text.base", stroke: red, {
5 | import draw: *
6 |
7 | content((0,0), [A letter: g], name: "text")
8 | hobby("text.north-west", (rel: (0, 1), to: ("text.north-east", 50%, "text.north-west")), "text.north-east", mark: (start: "|", end: ">"))
9 | }) with an inline canvas!
10 |
11 |
12 | This is an example #canvas(baseline: (0, 0), stroke: red, {
13 | import draw: *
14 |
15 | content((0,0), [Picture \ Picture \ Picture])
16 | }) with an inline canvas!
17 |
18 | By default #canvas(stroke: red, {
19 | import draw: *
20 |
21 | content((0,0), [Picture])
22 | }) is a "block level" element.
23 |
--------------------------------------------------------------------------------
/tests/catmul/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/catmul/ref/1.png
--------------------------------------------------------------------------------
/tests/catmul/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 | catmull((0,0), (1,0))
7 | }))
8 |
9 | #box(stroke: 2pt + red, canvas({
10 | import draw: *
11 | catmull((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2), k: .3)
12 | }))
13 |
14 | #box(stroke: 2pt + red, canvas({
15 | import draw: *
16 | catmull((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2))
17 | }))
18 |
19 | #box(stroke: 2pt + red, canvas({
20 | import draw: *
21 | catmull((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2), tension: .7)
22 | }))
23 |
24 | #box(stroke: 2pt + red, canvas({
25 | import draw: *
26 | catmull((0,-1), (1,1), (2,0), tension: .45, close: true, fill: blue)
27 | }))
28 |
--------------------------------------------------------------------------------
/tests/circle-through/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/circle-through/ref/1.png
--------------------------------------------------------------------------------
/tests/circle-through/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas(length: .5cm, {
5 | import draw: *
6 |
7 | let (a, b, c) = ((0,0), (2,-.5), (1,1))
8 | line(a, b, c, close: true, stroke: gray)
9 | circle-through(a, b, c, name: "c")
10 | circle("c.center", radius: .05, fill: red)
11 | }))
12 |
--------------------------------------------------------------------------------
/tests/circle/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/circle/ref/1.png
--------------------------------------------------------------------------------
/tests/circle/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case(radius => {
6 | import draw: *
7 |
8 | circle((0, 0), radius: radius, name: "c")
9 | point("c.center", "M")
10 | }, args: (1, 1cm, (1, .5), (1cm, .5), (.5, 1), (.5, 1cm)))
11 |
12 | #test-case(outer => {
13 | import draw: *
14 |
15 | let center = (1, 1)
16 | circle(center, outer)
17 | move-to(center)
18 | point(outer, "O")
19 | point(center, "M")
20 | }, args: ((2, 1), (rel: (1, 0)), (rel: (1, 1))))
21 |
22 | #test-case({
23 | import draw: *
24 |
25 | for z in range(-1, 2) {
26 | circle((0,0,z))
27 | }
28 | })
29 |
--------------------------------------------------------------------------------
/tests/content-anchors/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-anchors/ref/1.png
--------------------------------------------------------------------------------
/tests/content-anchors/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 | #import draw: content, rotate, scale, translate
5 |
6 | #test-case({
7 | import draw: *
8 | content((0, 0), text(size: 40pt)[Yogurt], padding: (rest: 1, top: 2), frame: "rect", name: "content")
9 | line("content.base-west", "content.base-east", stroke: green)
10 | for-each-anchor("content", name => {
11 | content((), text(size: 6pt)[#name], frame: "rect",
12 | fill: white, stroke: none)
13 | })
14 | })
15 |
16 | #for a in ("center", "north", "south", "east", "west", "north-east", "north-west", "south-east", "south-west", "mid", "base") {
17 | test-case({
18 | cross((0,0))
19 | content((0,0), [#a], anchor: a)
20 | })
21 |
22 | test-case({
23 | cross((0,0))
24 | rotate(45deg)
25 | content((0,0), [#a (rotate)], anchor: a)
26 | })
27 |
28 | test-case({
29 | cross((0,0))
30 | translate((1,1))
31 | cross((0,0))
32 | content((0,0), [#a (translate)], anchor: a)
33 | })
34 |
35 | test-case({
36 | cross((0,0))
37 | scale(2)
38 | cross((0,0))
39 | content((0,0), [#a (scale)], anchor: a)
40 | })
41 | }
42 |
--------------------------------------------------------------------------------
/tests/content-intersection/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-intersection/ref/1.png
--------------------------------------------------------------------------------
/tests/content-intersection/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | set-style(fill: gray, stroke: gray)
8 |
9 | intersections("i", {
10 | content((0,0), [Text])
11 | on-layer(-1, {
12 | line((1,1), (-1,-1))
13 | bezier((-1,0), (1,0), (-.5,.5), (.5,-.5), fill: none)
14 | })
15 | })
16 | on-layer(-1, {
17 | for-each-anchor("i", n => {
18 | circle("i." + n, radius: .05)
19 | })
20 | })
21 | })
22 |
23 | #test-case({
24 | import draw: *
25 |
26 | draw.content(name: "test1", frame: "rect", (0,0))[Test 1]
27 | draw.content(name: "test2", frame: "rect", (-1,-1))[Test 2]
28 | draw.line("test1", "test2")
29 | })
30 |
31 | #test-case({
32 | let thide = hide
33 | import draw: *
34 |
35 | draw.content(name: "test1", (0,0))[Test 1]
36 | draw.content((-1,-1))[#box(stroke: 1pt + red, thide[Test 2])]
37 | draw.content(name: "test2", frame: "rect", anchor: "north-east", (-1,-1))[Test 2]
38 | draw.line("test1", "test2")
39 | })
40 |
41 | #test-case({
42 | let thide = hide
43 | import draw: *
44 |
45 | draw.content(name: "test1", (0,0))[Test 1]
46 | draw.content((-1,-1))[#box(stroke: 1pt + red, thide[Test 2])]
47 | draw.content(name: "test2", frame: "rect", anchor: "south", (-1,-1))[Test 2]
48 | draw.line("test1", "test2")
49 | })
50 |
51 | #test-case({
52 | import draw:*
53 | content((-1,0), [Text], name: "a")
54 | content((+1,0), [Text], name: "b")
55 | line("a", "b")
56 | })
57 |
--------------------------------------------------------------------------------
/tests/content-padding/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-padding/ref/1.png
--------------------------------------------------------------------------------
/tests/content-padding/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | // All Sides
6 | #test-case({
7 | import draw: *
8 | content((0,0), [This is a test.], padding: .5, frame: "rect")
9 | })
10 |
11 | // Array Syntax
12 | #test-case({
13 | import draw: *
14 | // Y, X
15 | content((0,0), [This is a test.], padding: (.5, 0), frame: "rect")
16 | content((0,1), [This is a test.], padding: (0, .5), frame: "rect")
17 | // Top, Y, Bottom
18 | content((0,2), [This is a test.], padding: (.5, 0, 0), frame: "rect")
19 | content((0,3), [This is a test.], padding: (0, 0, .5), frame: "rect")
20 | // Top, Right, Bottom, Left
21 | content((0,4), [This is a test.], padding: (.5, 0, 0, 0), frame: "rect")
22 | content((0,5), [This is a test.], padding: (0, .5, 0, 0), frame: "rect")
23 | content((0,6), [This is a test.], padding: (0, 0, .5, 0), frame: "rect")
24 | content((0,7), [This is a test.], padding: (0, 0, 0, .5), frame: "rect")
25 | })
26 |
27 | // Dictionary Syntax
28 | #test-case({
29 | import draw: *
30 | content((0,0), [This is a test.], padding: (left: .5), frame: "rect")
31 | content((0,1), [This is a test.], padding: (right: .5), frame: "rect")
32 | content((0,2), [This is a test.], padding: (top: .5), frame: "rect")
33 | content((0,3), [This is a test.], padding: (bottom: .5), frame: "rect")
34 | content((0,4), [This is a test.], padding: (:), frame: "rect")
35 | })
36 |
--------------------------------------------------------------------------------
/tests/content-rotation/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-rotation/ref/1.png
--------------------------------------------------------------------------------
/tests/content-rotation/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | // Test aabb
6 | #for angle in (0deg, 30deg, -30deg, 45deg, -45deg, 90deg, -90deg) {
7 | test-case({
8 | import draw: *
9 | content((), [Content], angle: angle)
10 | })
11 | }
12 |
13 | // Rotate to coordinate
14 | #for angle in (0deg, 30deg, -30deg, 45deg, -45deg, 90deg, -90deg) {
15 | test-case({
16 | import draw: *
17 | let pt = (angle, 2)
18 | line((0,0), pt)
19 | content((0,0), [Content], angle: pt)
20 | })
21 | }
22 |
--------------------------------------------------------------------------------
/tests/content-rtl/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-rtl/ref.png
--------------------------------------------------------------------------------
/tests/content-rtl/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-rtl/ref/1.png
--------------------------------------------------------------------------------
/tests/content-rtl/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #set text(dir: rtl)
6 |
7 | #test-case({
8 | import draw: *
9 |
10 | line((0,0), (1,0), mark: (end: ">"))
11 | content((0,1), [This is an example of RTL.])
12 | line((0,0), (45deg, 1), mark: (end: ">"))
13 | })
14 |
--------------------------------------------------------------------------------
/tests/content-span/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-span/ref/1.png
--------------------------------------------------------------------------------
/tests/content-span/test.typ:
--------------------------------------------------------------------------------
1 | #import "/src/lib.typ": *
2 | #import "/tests/helper.typ": *
3 | #set page(width: auto, height: auto)
4 |
5 | #test-case({
6 | import draw: *
7 | content((0,0), (+1,+1), align(center + horizon)[tr], frame: "rect")
8 | content((0,0), (-1,-1), align(center + horizon)[bl], frame: "rect")
9 | content((0,0), (-1,+1), align(center + horizon)[tl], frame: "rect")
10 | content((0,0), (+1,-1), align(center + horizon)[br], frame: "rect")
11 | })
12 |
--------------------------------------------------------------------------------
/tests/content-transform/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content-transform/ref/1.png
--------------------------------------------------------------------------------
/tests/content-transform/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let test() = {
6 | import draw: *
7 | content((0,0), [This is a test.], padding: .1, name: "e")
8 | for-each-anchor("e", n => {
9 | circle("e." + n, radius: .05)
10 | })
11 | }
12 |
13 | #test-case({
14 | import draw: *
15 | cross((0,0))
16 | scale(2.5)
17 | cross((0,0))
18 | test()
19 | })
20 |
21 | #test-case({
22 | import draw: *
23 | cross((0,0))
24 | rotate(45deg)
25 | cross((0,0))
26 | test()
27 | })
28 |
29 | #test-case({
30 | import draw: *
31 | cross((0,0))
32 | translate((1,2,1))
33 | cross((0,0))
34 | test()
35 | })
36 |
--------------------------------------------------------------------------------
/tests/content/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/content/ref/1.png
--------------------------------------------------------------------------------
/tests/content/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | content((0,0), [This is a test.])
8 | })
9 |
10 | #test-case({
11 | import draw: *
12 | content((0,0), auto, [This is a test.], frame: "rect")
13 | })
14 |
15 | #test-case({
16 | import draw: *
17 | content((0,0), (1.5,1), [This is a test.], frame: "rect")
18 | })
19 |
20 | #test-case({
21 | import draw: *
22 | content((0,0), (1,1.5), [This is a test.], frame: "rect")
23 | })
24 |
25 | #test-case({
26 | import draw: *
27 | content((0,0), auto, angle: 45deg, [This is a test.], frame: "rect")
28 | })
29 |
30 | #test-case({
31 | import draw: *
32 | content((0,0), (1,1.5), angle: 45deg, [This is a test.], frame: "rect")
33 | })
34 |
35 | #test-case({
36 | import draw: *
37 | content((0,0), (1.5,1), angle: 45deg, [This is a test.], frame: "rect")
38 | })
39 |
40 | #test-case({
41 | import draw: *
42 | content((0,0), auto, angle: 0deg, [This is a test.], frame: "circle")
43 | })
44 |
45 | #test-case({
46 | import draw: *
47 | content((0,0), auto, angle: 45deg, [This is a test.], frame: "circle")
48 | })
49 |
50 | #test-case({
51 | import draw: *
52 | content((0,0), (1,1.5), angle: 45deg, [This is a test.], frame: "circle")
53 | })
54 |
55 | #test-case({
56 | import draw: *
57 | set-style(content: (frame: "circle", stroke: 3pt), fill: blue)
58 | content((0,0), (1,1), angle: 15deg,
59 | text(white, align(center+horizon)[With style!]))
60 | })
61 |
62 | #test-case({
63 | import draw: *
64 | circle((0,0), name: "c")
65 | content((0,0), angle: "c.north-east", [Text])
66 | })
67 |
68 | // Test the z coordinate is respected
69 | #test-case({
70 | import draw: *
71 | content((0, 0,-1), [Z=-1])
72 | content((0, 0, 0), [Z=0])
73 | content((0, 0, 1), [Z=1])
74 | })
75 |
76 | // Test inline math measuring
77 | #test-case({
78 | import draw: *
79 | content((0, 0), $x$)
80 | })
81 |
82 | #test-case({
83 | import draw: *
84 |
85 | let elements = ("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l")
86 |
87 | line((1, 4), (13, 4), (13, 3), (1, 3), close: true)
88 |
89 | for i in range(1, 13) {
90 | line((i, 4), (i, 3))
91 | content((i + 0.5, 3.5), text(bottom-edge:"descender", top-edge: "ascender")[#elements.at(i - 1)])
92 | }
93 | })
94 |
95 | #test-case({
96 | import draw:*
97 | content((-1,0), [Text], name: "a")
98 | content((+1,0), [Text], name: "b")
99 | line("a", "b")
100 | })
101 |
102 | // #792 Scaling
103 | #test-case({
104 | import draw:*
105 | scale(2)
106 | set-style(content: (auto-scale: false))
107 | content((0,0), [Text])
108 | set-style(content: (auto-scale: true))
109 | content((0,1), [Text])
110 | })
111 |
112 | // Compiler crash
113 | #test-case({
114 | import draw: *
115 | rect((-1,-1), (1,1))
116 | content((0,0), [Test], padding: -1, frame: "rect")
117 | })
118 |
--------------------------------------------------------------------------------
/tests/coordinate-lerp/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/coordinate-lerp/ref/1.png
--------------------------------------------------------------------------------
/tests/coordinate-lerp/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | grid((-2,-1), (7,1), stroke: gray)
8 |
9 | let a = (1,0)
10 | let b = (4,0)
11 |
12 | set-style(circle: (radius: .1))
13 | for i in (-50%, 0%, 50%, 100%, 150%) {
14 | let pt = (a, i, b)
15 | circle(pt)
16 | content(pt, repr(i), anchor: "north", padding: (top: .5))
17 | }
18 | })
19 |
20 | #test-case({
21 | import draw: *
22 | grid((-2,-1), (7,1), stroke: gray)
23 |
24 | let a = (1,0)
25 | let b = (4,0)
26 |
27 | set-style(circle: (radius: .1))
28 | for i in (-1.5, 0, 1.5, 3, 4.5) {
29 | let pt = (a, i, b)
30 | circle(pt)
31 | content(pt, repr(i), anchor: "north", padding: (top: .5))
32 | }
33 | })
34 |
35 |
36 | #test-case({
37 | import draw: *
38 | grid((-2,-1), (7,1), stroke: gray)
39 |
40 | let a = (1,0)
41 | let b = (4,0)
42 |
43 | set-style(circle: (radius: .1))
44 | for i in (-1.5cm, 0cm, 1.5cm, 3cm, 4.5cm) {
45 | let pt = (a, i, b)
46 | circle(pt)
47 | content(pt, repr(i), anchor: "north", padding: (top: .5))
48 | }
49 | })
50 |
51 | #test-case({
52 | import draw: *
53 | grid((0,-3), (5,4), stroke: gray)
54 |
55 | let a = (1,0)
56 | let b = (4,0)
57 |
58 | set-style(circle: (radius: .1))
59 | circle(a, fill: red)
60 | circle(b, fill: green)
61 |
62 | for i in (-50%, 0%, 50%, 100%) {
63 | let pt = (a, i, 90deg, b)
64 | circle(pt)
65 | content(pt, repr(i), anchor: "north", padding: (top: .5))
66 | }
67 | })
68 |
69 | #test-case({
70 | import draw: *
71 | grid((0,-3), (3,4), stroke: gray)
72 |
73 | let a = (1,0)
74 | let b = (2,0)
75 |
76 | set-style(circle: (radius: .1))
77 | circle(a, fill: red)
78 | circle(b, fill: green)
79 |
80 | for i in (-2, 0, 1.5, 3) {
81 | let pt = (a, i, 90deg, b)
82 | circle(pt)
83 | content(pt, repr(i), anchor: "north", padding: (top: .5))
84 | }
85 | })
86 |
--------------------------------------------------------------------------------
/tests/coordinate/custom/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/coordinate/custom/ref/1.png
--------------------------------------------------------------------------------
/tests/coordinate/custom/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | grid((-2,-1), (7,1), stroke: gray)
8 |
9 | let log-resolver(ctx, coordinate) = {
10 | if type(coordinate) == dictionary and "log" in coordinate {
11 | coordinate = coordinate.log
12 | coordinate = coordinate.map(n => calc.log(calc.max(n, util.float-epsilon), base: 10))
13 | }
14 |
15 | return coordinate
16 | }
17 |
18 | register-coordinate-resolver(log-resolver)
19 |
20 | set-style(circle: (radius: .1))
21 | for i in (.1, 1, 10, 100, 1000, 10000) {
22 | let pt = (log: (i * 1, 1))
23 | circle(pt)
24 | content(pt, repr(i), anchor: "north", padding: (top: .5))
25 | }
26 | })
27 |
--------------------------------------------------------------------------------
/tests/copy-anchor/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/copy-anchor/ref/1.png
--------------------------------------------------------------------------------
/tests/copy-anchor/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas(length: 1cm, {
5 | import draw: *
6 |
7 | group(name: "b", {
8 | group(name: "a", {
9 | rect((-1,-1), (1,1))
10 | anchor("my-anchor", (0,0))
11 | })
12 |
13 | copy-anchors("a")
14 | circle("my-anchor", radius: .1, stroke: red)
15 | })
16 |
17 | circle("b.my-anchor", radius: .2, stroke: blue)
18 | }))
19 |
20 | #box(stroke: 2pt + red, canvas(length: 1cm, {
21 | import draw: *
22 |
23 | group(name: "a", {
24 | group(name: "b", {
25 | line((), (1,1), name: "l")
26 | })
27 | copy-anchors("b")
28 | circle("l.end")
29 | })
30 |
31 | circle("a.l.start")
32 | }))
--------------------------------------------------------------------------------
/tests/cube/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/cube/ref/1.png
--------------------------------------------------------------------------------
/tests/cube/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | line((0, 0, 1), (1, 0, 1), (1, 1, 1), (0, 1, 1), close: true)
8 | line((0, 0, 1), (0, 0, 0))
9 | line((1, 0, 1), (1, 0, 0))
10 | line((1, 1, 1), (1, 1, 0))
11 | line((0, 1, 1), (0, 1, 0))
12 | line((0, 0), (1, 0), (1, 1), (0, 1), close: true)
13 | }))
14 |
--------------------------------------------------------------------------------
/tests/custom-mark/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/custom-mark/ref/1.png
--------------------------------------------------------------------------------
/tests/custom-mark/test.typ:
--------------------------------------------------------------------------------
1 | #import "/src/lib.typ": *
2 | #import "/tests/helper.typ": *
3 | #set page(width: auto, height: auto)
4 |
5 | #let register-face() = {
6 | import draw: *
7 |
8 | register-mark("face", style => {
9 | circle((0,0), radius: .5, fill: yellow)
10 | arc((0,0), start: 180deg + 30deg, delta: 180deg - 60deg, anchor: "origin", radius: .3)
11 | circle((-.15, +.15), radius: .1, fill: white)
12 | circle((-.10, +.10), radius: .025, fill: black)
13 | circle((+.15, +.15), radius: .1, fill: white)
14 | circle((+.20, +.10), radius: .025, fill: black)
15 |
16 | anchor("tip", (+.5, 0))
17 | anchor("base", (-.5, 0))
18 | }, mnemonic: ":)")
19 | }
20 |
21 | #test-case({
22 | import draw: *
23 |
24 | register-face()
25 | catmull((-3, 0), (-1,1), (1,-1), (3,0), mark: (end: "face", start: (symbol: ":)", flip: true, reverse: true), ))
26 | })
27 |
28 | #test-case({
29 | import draw: *
30 |
31 | line((0,-1), (0,1), stroke: green)
32 |
33 | register-face()
34 | mark((0,0), (+1,0), symbol: ":)", slant: 50%, anchor: "center")
35 | })
36 |
37 | #test-case({
38 | import draw: *
39 |
40 | register-face()
41 | line((0,0), (3,0), mark: (end: (":)", ":)", ":)"), sep: -.3))
42 | })
43 |
--------------------------------------------------------------------------------
/tests/decorations/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/decorations/ref/1.png
--------------------------------------------------------------------------------
/tests/decorations/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | decorations.brace((-1,0), (1,0), stroke: blue, amplitude: 1, thickness: 50%, pointiness: 25%, outer-thickness: .1)
7 | })
8 |
9 | #test-case(args => {
10 | decorations.brace((-1,-1), (1,1), ..args)
11 | }, args: ((:), (flip: true)))
12 |
13 | #test-case(args => {
14 | decorations.brace((-1,0), (1,0), ..args)
15 | }, args: (
16 | (amplitude: .3),
17 | (pointiness: 0%),
18 | (pointiness: 50%),
19 | (pointiness: 100%),
20 | ))
21 |
22 | #test-case(args => {
23 | decorations.flat-brace((-1,-1), (1,1), ..args)
24 | }, args: ((:), (flip: true)))
25 |
26 | #test-case(args => {
27 | decorations.flat-brace((-1,0), (1,0), ..args)
28 | }, args: (
29 | (amplitude: .7),
30 | (curves: (.5, 0, 0, 0), outer-curves: 1),
31 | (aspect: .3),
32 | ))
33 |
34 | // Bug #577
35 | #test-case(args => {
36 | decorations.brace((-1,0), (1,0), ..args, pointiness: 100%)
37 | }, args: (
38 | (amplitude: 0.5),
39 | (amplitude: 1),
40 | ))
41 |
42 | #test-case(args => {
43 | decorations.brace((-1,0), (1,0), ..args, pointiness: 0%)
44 | }, args: (
45 | (amplitude: 0.5),
46 | (amplitude: 1),
47 | ))
48 |
49 | // Bug #687
50 | #test-case(args => {
51 | decorations.flat-brace((-1,-1), (1,1), ..args, name: "brace")
52 | draw.circle("brace.content", radius: 0.1);
53 | }, args: (
54 | (flip: false),
55 | (flip: true),
56 | ))
57 |
58 | #test-case(args => {
59 | decorations.brace((-1,-1), (1,1), ..args, name: "brace")
60 | draw.circle("brace.content", radius: 0.1);
61 | }, args: (
62 | (flip: false),
63 | (flip: true),
64 | ))
65 |
66 | #test-case({
67 | decorations.flat-brace((0,0), (1,0), stroke: blue, fill: gray)
68 | decorations.brace((0,1), (1,1), stroke: blue, fill: gray, taper: false)
69 | })
70 |
--------------------------------------------------------------------------------
/tests/element-anchors/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/element-anchors/ref.png
--------------------------------------------------------------------------------
/tests/element-anchors/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/element-anchors/ref/1.png
--------------------------------------------------------------------------------
/tests/element-anchors/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let display(body, ..args) = {
5 | import draw: *
6 | (body)(..args, name: "elem");
7 | get-ctx(ctx => {
8 | for-each-anchor(
9 | "elem",
10 | exclude: if args.named().at("mode", default: none) == "OPEN" {
11 | ("east", "north-east", "north", "south", "south-east")
12 | } else {()},
13 | o => {
14 | let n = "elem." + o
15 |
16 | group({
17 | rotate(45deg)
18 | set-style(stroke: blue)
19 | line((rel: (-.1, 0), to: n), (rel: (.2, 0)))
20 | line((rel: (0, -.1), to: n), (rel: (0, .2)))
21 | })
22 |
23 | let (_, nv) = coordinate.resolve(ctx, n)
24 | let (x, y, ..) = nv
25 | let anchor = (
26 | (if y < 0 { "north" } else if y > 0 { "south" },) + (if x < 0 { "east" } else if x > 0 { "west" },)
27 | ).filter(p => p != none).join("-")
28 | if anchor == none {
29 | anchor = "south"
30 | }
31 |
32 | content(n, text(8pt, o), anchor: anchor, padding: .2)
33 | }
34 | )
35 | })
36 | }
37 |
38 | #box(stroke: 2pt + red, canvas(length: 1cm, {
39 | import draw: *
40 | display(line, (0,0), (2,1), (4,0))
41 | }))
42 |
43 | #box(stroke: 2pt + red, canvas(length: 1cm, {
44 | import draw: *
45 | display(circle, ())
46 | }))
47 |
48 | #box(stroke: 2pt + red, canvas(length: 1cm, {
49 | import draw: *
50 | display(circle-through, (-1,0), (0,1), (1,0))
51 | }))
52 |
53 | #box(stroke: 2pt + red, canvas(length: 1cm, {
54 | import draw: *
55 | display(arc, (0,0), start: 225deg, stop: 135deg, radius: 5, mode: "OPEN")
56 | }))
57 |
58 | #box(stroke: 2pt + red, canvas(length: 1cm, {
59 | import draw: *
60 | display(arc, (0,0), start: 225deg, stop: 135deg, radius: 5, mode: "PIE")
61 | }))
62 |
63 | #box(stroke: 2pt + red, canvas(length: 1cm, {
64 | import draw: *
65 | display(arc, (0,0), start: 225deg, stop: 135deg, radius: 5, mode: "CLOSE")
66 | }))
67 |
68 | #box(stroke: 2pt + red, canvas(length: 1cm, {
69 | import draw: *
70 | display(line, (-1,0), (0,1), (1,0))
71 | }))
72 |
73 | #box(stroke: 2pt + red, canvas(length: 1cm, {
74 | import draw: *
75 | display(grid, (-1,-1), (1,1), step: 1)
76 | }))
77 |
78 | #box(stroke: 2pt + red, canvas(length: 1cm, {
79 | import draw: *
80 | display(content, (), text(2cm)[Text])
81 | }))
82 |
83 | #box(stroke: 2pt + red, canvas(length: 1cm, {
84 | import draw: *
85 | display(rect, (-1,-1), (1,1))
86 | }))
87 |
88 | #box(stroke: 2pt + red, canvas(length: 1cm, {
89 | import draw: *
90 | display(rect, (-1,-1), (1,1), radius: .5)
91 | }))
92 |
93 | #box(stroke: 2pt + red, canvas(length: 1cm, {
94 | import draw: *
95 | display(bezier, (-2,0), (2,0), (-1,1), (1,-1))
96 | }))
97 |
98 | #box(stroke: 2pt + red, canvas(length: 1cm, {
99 | import draw: *
100 | display(bezier, (-1,-1), (1,-1), (0,2))
101 | }))
102 |
103 | #box(stroke: 2pt + red, canvas(length: 1cm, {
104 | import draw: *
105 | display(bezier-through, (-1,-1), (0,1), (1,-1))
106 | }))
107 |
108 | #box(stroke: 2pt + red, canvas(length: 1cm, {
109 | import draw: *
110 | display(catmull, (-2,0), (-1,-1), (0,1), (1,-1), (2,0))
111 | }))
112 |
--------------------------------------------------------------------------------
/tests/empty-group/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/empty-group/ref/1.png
--------------------------------------------------------------------------------
/tests/empty-group/test.typ:
--------------------------------------------------------------------------------
1 | #import "/src/lib.typ": *
2 | #import "/tests/helper.typ": *
3 |
4 | #test-case({
5 | import draw: *
6 |
7 | group(none)
8 | group(ctx => none)
9 | })
10 |
11 | #test-case({
12 | import draw: *
13 | group({
14 | group(name: "group-1", none)
15 | copy-anchors("group-1")
16 | })
17 | group({
18 | group(name: "group-2", {
19 | anchor("default", (0,1))
20 | })
21 | copy-anchors("group-2")
22 | })
23 | })
--------------------------------------------------------------------------------
/tests/empty/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/empty/ref/1.png
--------------------------------------------------------------------------------
/tests/empty/test.typ:
--------------------------------------------------------------------------------
1 | // Empty test file
2 |
--------------------------------------------------------------------------------
/tests/floating/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/floating/ref/1.png
--------------------------------------------------------------------------------
/tests/floating/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | rect((0,0), (5,5))
8 |
9 | // Floating circle should not affect bounds
10 | floating(circle((6,6)))
11 |
12 | // Floating content
13 | floating(content((2.5, 6), [Floating content]))
14 |
15 | // Multiple floating elements
16 | floating({
17 | rect((-1,3), (0,2))
18 | rect((0,2), (1,1))
19 | })
20 |
21 | // Styles apply to floating elementss
22 | set-style(stroke: green)
23 |
24 | // Use floating anchor
25 | floating(circle((5,2), name: "floating-circle"))
26 | line("floating-circle", (0,0))
27 | })
28 |
29 | // The example used in `floating` docstring
30 | #test-case({
31 | import draw: *
32 |
33 | group({
34 | circle((0,0))
35 | content((0,2), [Non-floating])
36 | floating(content((2,0), [Floating]))
37 | }, name: "bounds")
38 |
39 | set-style(stroke: red)
40 | rect("bounds.north-west", "bounds.south-east")
41 | })
--------------------------------------------------------------------------------
/tests/gradient/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/gradient/ref/1.png
--------------------------------------------------------------------------------
/tests/gradient/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 |
8 | fill(gradient.linear(red, blue))
9 |
10 | rect((2,2), (4,4))
11 | circle((0,0))
12 | line((0,2), (1,3), (0, 4), (-3, 3), close: true)
13 | })
14 |
--------------------------------------------------------------------------------
/tests/grid/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/grid/ref/1.png
--------------------------------------------------------------------------------
/tests/grid/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | grid((0,0), (1,1), step: .1)
8 |
9 | translate((0, 1.5))
10 | grid((0,0), (1,1), step: .5)
11 |
12 | translate((0, 1.5))
13 | grid((0,0), (1,1), step: (x: .2, y: .5))
14 | }))
15 |
--------------------------------------------------------------------------------
/tests/group-anchors/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-anchors/ref/1.png
--------------------------------------------------------------------------------
/tests/group-anchors/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import cetz.draw: *
7 |
8 | set-style(circle: (stroke: none, fill: gray))
9 |
10 | circle((0, 0), radius: .1cm, fill: blue)
11 | content((0, 0), [(0,0)], anchor: "north", padding: .1)
12 |
13 | group(name: "group", {
14 | anchor("default", (0, 0))
15 | rect((-1, 0), (2, 2))
16 | }, anchor: "north")
17 |
18 | on-layer(-1, {
19 | for-each-anchor("group", name => {
20 | circle("group." + name, radius: .1cm, fill: gray, stroke: none)
21 | })
22 | })
23 | })
24 |
--------------------------------------------------------------------------------
/tests/group-nested-anchors/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-nested-anchors/ref/1.png
--------------------------------------------------------------------------------
/tests/group-nested-anchors/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | group(name: "g", {
8 | group(name: "inner-1", {
9 | group(name: "inner-2", {
10 | rect((-1,-1), (1,1))
11 | anchor("p1", (1,1))
12 | })
13 | copy-anchors("inner-2")
14 | anchor("p2", (-1,-1))
15 | })
16 | copy-anchors("inner-1")
17 | })
18 |
19 | circle("g.p1", fill: blue)
20 | circle("g.p2", fill: red)
21 | }))
22 |
23 | #box(stroke: 2pt + red, canvas({
24 | import draw: *
25 |
26 | group(name: "parent", {
27 | content((0,0), [Content], name: "content")
28 | group(name: "child", {
29 | circle((1,-2), fill: blue, name: "circle")
30 | })
31 | })
32 |
33 | rect("parent.content.south-west",
34 | "parent.content.north-east", stroke: green)
35 | rect(
36 | "parent.child.circle.-45deg",
37 | "parent.child.circle.135deg",
38 | stroke: green
39 | )
40 | }))
--------------------------------------------------------------------------------
/tests/group-none/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-none/ref.png
--------------------------------------------------------------------------------
/tests/group-none/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-none/ref/1.png
--------------------------------------------------------------------------------
/tests/group-none/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 |
8 | group({})
9 | })
10 |
--------------------------------------------------------------------------------
/tests/group-padding/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-padding/ref/1.png
--------------------------------------------------------------------------------
/tests/group-padding/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let show-group(padding: none) = {
5 | draw.group(padding: padding, {
6 | draw.rect((0,0), (1,1), fill: blue)
7 | }, name: "g")
8 | draw.rect("g.south-west", "g.north-east")
9 | }
10 |
11 | #box(stroke: 2pt + red, canvas({
12 | import draw: *
13 | show-group()
14 | }))
15 |
16 | #box(stroke: 2pt + red, canvas({
17 | import draw: *
18 | show-group(padding: 1)
19 | }))
20 |
21 | #box(stroke: 2pt + red, canvas({
22 | import draw: *
23 | show-group(padding: (0, 1))
24 | }))
25 |
26 | #box(stroke: 2pt + red, canvas({
27 | import draw: *
28 | show-group(padding: (1, 0))
29 | }))
30 |
31 | #box(stroke: 2pt + red, canvas({
32 | import draw: *
33 | show-group(padding: (top: 1))
34 | }))
35 |
36 | #box(stroke: 2pt + red, canvas({
37 | import draw: *
38 | show-group(padding: (bottom: 1))
39 | }))
40 |
41 | #box(stroke: 2pt + red, canvas({
42 | import draw: *
43 | show-group(padding: (left: 1))
44 | }))
45 |
46 | #box(stroke: 2pt + red, canvas({
47 | import draw: *
48 | show-group(padding: (right: 1))
49 | }))
50 |
--------------------------------------------------------------------------------
/tests/group-transform/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-transform/ref/1.png
--------------------------------------------------------------------------------
/tests/group-transform/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let show-group(body: ()) = {
5 | draw.group({
6 | body + draw.rect((-2,-2), (2,2))
7 | }, name: "g")
8 | draw.for-each-anchor("g", n => {
9 | draw.content("g."+n, n)
10 | })
11 | }
12 |
13 | #box(stroke: 2pt + red, canvas({
14 | import draw: *
15 |
16 | translate((1,1,1))
17 | show-group()
18 | }))
19 |
20 | #box(stroke: 2pt + red, canvas({
21 | import draw: *
22 |
23 | scale(x: 2, y: 50%)
24 | show-group()
25 | }))
26 |
27 | #box(stroke: 2pt + red, canvas({
28 | import draw: *
29 |
30 | rotate(30deg)
31 | show-group()
32 | }))
33 |
34 | #box(stroke: 2pt + red, canvas({
35 | import draw: *
36 |
37 | show-group(body: translate((1,1,1)))
38 | }))
39 |
40 | #box(stroke: 2pt + red, canvas({
41 | import draw: *
42 |
43 | show-group(body: scale(x: 200%, y: .5))
44 | }))
45 |
46 | #box(stroke: 2pt + red, canvas({
47 | import draw: *
48 |
49 | show-group(body: rotate(30deg))
50 | }))
51 |
--------------------------------------------------------------------------------
/tests/group-translate/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/group-translate/ref/1.png
--------------------------------------------------------------------------------
/tests/group-translate/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let cross(pos: (0,0)) = {
5 | draw.line((rel: (-.2,0), to: pos),
6 | (rel: (.4,0)), stroke: blue + 2pt)
7 | draw.line((rel: (0,-.2), to: pos),
8 | (rel: (0,.4)), stroke: blue + 2pt)
9 | }
10 |
11 | /* Test the translation of grouped elements
12 | via the group anchor. */
13 | #box(stroke: 2pt + red, canvas({
14 | import draw: *
15 |
16 | cross()
17 | set-style(content: (padding: 1))
18 | group({
19 | content((0,0), [Center])
20 | })
21 | group({
22 | content((0,0), [North])
23 | }, anchor: "north")
24 | group({
25 | content((0,0), [South])
26 | }, anchor: "south")
27 | group({
28 | content((0,0), [West])
29 | }, anchor: "west")
30 | group({
31 | content((0,0), [East])
32 | }, anchor: "east")
33 | group({
34 | content((0,0), [North-West])
35 | }, anchor: "north-west")
36 | group({
37 | content((0,0), [North-East])
38 | }, anchor: "north-east")
39 | group({
40 | content((0,0), [South-West])
41 | }, anchor: "south-west")
42 | group({
43 | content((0,0), [South-East])
44 | }, anchor: "south-east")
45 | group({
46 | anchor("custom", (0,-2))
47 | content((0,0), [Custom])
48 | }, anchor: "custom")
49 | }))
50 |
--------------------------------------------------------------------------------
/tests/helper.typ:
--------------------------------------------------------------------------------
1 | #import "/src/lib.typ" as cetz
2 |
3 | /// Draw a point + label
4 | #let point(pt, name) = {
5 | cetz.draw.circle(pt, radius: .05cm, fill: black, stroke: none, name: "pt")
6 | cetz.draw.content((rel: (.2cm, 0), to: "pt"), [#name], anchor: "west")
7 | }
8 |
9 | /// Draw a cross at position pt
10 | #let cross(pt, size: .25, ..style) = {
11 | import cetz.draw: *
12 | let len = size / 2
13 | line((rel: (-len,0), to: pt),
14 | (rel: (len, 0), to: pt), stroke: green, ..style)
15 | line((rel: (0,-len), to: pt),
16 | (rel: (0, len), to: pt), stroke: green, ..style)
17 | }
18 |
19 | /// Test case canvas surrounded by a red border
20 | #let test-case(body, ..canvas-args, args: none) = {
21 | if type(body) != function {
22 | body = _ => { body }
23 | args = (none,)
24 | } else {
25 | assert(type(args) == array and args.len() > 0,
26 | message: "Function body requires args set!")
27 | }
28 |
29 | for arg in args {
30 | block(stroke: 2pt + red,
31 | cetz.canvas(..canvas-args, {
32 | body(arg)
33 | })
34 | )
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/hide/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/hide/ref/1.png
--------------------------------------------------------------------------------
/tests/hide/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | rect((0,0), (5,5))
8 |
9 | // Hide a circle
10 | hide(circle((6,6)))
11 |
12 | // Hide content
13 | hide(content((-6,-6), [Hidden]))
14 |
15 | // Hide multiple elements
16 | hide({
17 | rect((0,0), (1,1))
18 | rect((1,1), (2,2))
19 | rect((2,2), (3,3))
20 | })
21 |
22 | // Use hidden anchor
23 | hide(line((0,0), (2.5, 2.5), name: "line"))
24 | content("line.end", [Hidden anchor])
25 | })
26 |
27 | #test-case({
28 | import draw: *
29 |
30 | merge-path({
31 | arc((0,0), start: 0deg, stop: 180deg)
32 | hide({
33 | // This gets ignored
34 | line((), (rel: (-5,0), update: false))
35 | })
36 | line((), (rel: (1, -1)))
37 | }, close: true)
38 | })
39 |
40 | #test-case({
41 | import draw: *
42 |
43 | hide(line((-1,-1), (1,1)), bounds: true)
44 | })
45 |
--------------------------------------------------------------------------------
/tests/hobby/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/hobby/ref.png
--------------------------------------------------------------------------------
/tests/hobby/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/hobby/ref/1.png
--------------------------------------------------------------------------------
/tests/hobby/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 | hobby((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2), omega: 0)
8 | })
9 |
10 | #test-case({
11 | import draw: *
12 | hobby((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2), omega: .5)
13 | })
14 |
15 | #test-case({
16 | import draw: *
17 | hobby((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2), omega: 1)
18 | })
19 |
20 | #test-case({
21 | import draw: *
22 | hobby((0,-1), (1,1), (2,0), (3,1), (4,0), (5,2), close: true, fill: blue)
23 | })
24 |
25 | // Two points, not closed
26 | #test-case({
27 | import draw: *
28 | hobby((0,0), (1,1))
29 | })
30 |
31 | // Two points, closed
32 | #test-case({
33 | import draw: *
34 | hobby((0,0), (1,1), close: true)
35 | })
36 |
--------------------------------------------------------------------------------
/tests/image/image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/image/image.png
--------------------------------------------------------------------------------
/tests/image/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/image/ref/1.png
--------------------------------------------------------------------------------
/tests/image/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | content(
8 | (0,0),
9 | image("image.png", width: 2cm),
10 | anchor: "north-west",
11 | name: "i"
12 | )
13 |
14 | set-style(radius: .1, fill: blue)
15 | for-each-anchor("i", anchor => {
16 | circle("i." + anchor)
17 | })
18 |
19 | fill(red);
20 | circle(("i.north-west", 75%, "i.north-east"))
21 | }))
22 |
--------------------------------------------------------------------------------
/tests/intersection/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/intersection/ref/1.png
--------------------------------------------------------------------------------
/tests/intersection/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let test(body) = canvas(length: 1cm, {
6 | import draw: *
7 |
8 | group({
9 | intersections("i", {
10 | body
11 | })
12 | for-each-anchor("i", (name) => {
13 | circle("i."+name, radius: .1, fill: red)
14 | })
15 | })
16 | })
17 |
18 | #box(stroke: 2pt + red, {
19 | import draw: *
20 | test({
21 | line((-1,-1), (1,1))
22 | })
23 | test({
24 | line((-1,-1), (1,1))
25 | line((-1,1), (1,-1))
26 | })
27 | test({
28 | line((-1,.5),(1,.5))
29 | line((-1,-1), (1,1))
30 | line((-1,1), (1,-1))
31 | })
32 | test({
33 | circle((0,0))
34 | line((-1,-1), (1,1))
35 | })
36 | test({
37 | circle((0,0))
38 | line((-1,.5),(1,.5))
39 | })
40 | test({
41 | bezier-through((-1,0), (0,1), (1,0))
42 | line((-1,.5),(1,.5))
43 | })
44 | test({
45 | bezier-through((-1,0), (0,.5), (1,0))
46 | circle((0,0), radius: .8)
47 | })
48 | test({
49 | bezier-through((-1,0), (0,.5), (1,0))
50 | bezier-through((-1,.5), (0,-.5), (1,.5))
51 | })
52 | test({
53 | bezier((-1,-1), (1,1), (-.5,2), (.5,-2))
54 | bezier((-1,1), (1,-1), (-.5,-2), (.5,2))
55 | })
56 | test({
57 | grid((0,0), (2,2), step: 1)
58 | })
59 | test({
60 | rect((0,0), (2,2))
61 | rotate(45deg)
62 | line((0,0), (calc.sqrt(2*calc.pow(2,2)),0))
63 | })
64 | test({
65 | // The marks must not generate intersections with the line!
66 | line((0,0), (2,2), mark: (start: ">", end: ">"))
67 | })
68 | })
69 |
70 | #test-case({
71 | import draw: *
72 |
73 | intersections("i", {
74 | content((0, 0), [This is\ Text!], frame: "circle", name: "a")
75 | content((2, 1), [Hello!], frame: "circle", name: "b")
76 | // Invisible intersection line
77 | line("a.default", "b.default", stroke: none)
78 | })
79 | line("i.0", "i.1", mark: (end: ">"))
80 | })
81 |
82 | #test-case({
83 | import draw: *
84 |
85 | circle((0,0), name: "a")
86 | rect((0,0), (2,2), name: "b")
87 | intersections("i", "a", "b", {
88 | line((-1,-1), (1,1))
89 | })
90 | for-each-anchor("i", (name) => {
91 | circle("i."+name, radius: .1, fill: red)
92 | })
93 | })
94 |
95 | #test-case(fn => {
96 | import draw: *
97 |
98 | let c = circle((1,1), name: "a", radius: 1.25)
99 | let r = rect((0,0), (2,2), name: "b")
100 | intersections("i", r, c, sort: fn)
101 |
102 | for-each-anchor("i", (name) => {
103 | content((), [#name], frame: "circle", fill: white)
104 | })
105 | }, args: (
106 | none,
107 | sorting.points-by-angle.with(reference: (1, 1)),
108 | sorting.points-by-distance.with(reference: (0, 0.1)),
109 | ))
110 |
--------------------------------------------------------------------------------
/tests/layer/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/layer/ref/1.png
--------------------------------------------------------------------------------
/tests/layer/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 |
8 | circle((0,0), fill: red, stroke: none)
9 | on-layer(0, {
10 | circle((1, 0), fill: green, stroke: none)
11 | })
12 | on-layer(1, {
13 | circle((2, 0), fill: blue, stroke: none)
14 | })
15 | })
16 |
17 | #test-case({
18 | import draw: *
19 |
20 | on-layer(2, {
21 | circle((2, 0), fill: blue, stroke: none)
22 | })
23 | on-layer(1, {
24 | circle((1, 0), fill: green, stroke: none)
25 | })
26 | circle((0,0), fill: red, stroke: none)
27 | })
28 |
29 | // Test nested layers
30 | #test-case({
31 | import draw: *
32 |
33 | on-layer(1, {
34 | circle((1, 0), fill: green, stroke: none, name: "c2")
35 | on-layer(0, {
36 | circle((0,0), fill: red, stroke: none)
37 | })
38 | })
39 |
40 | on-layer(1, {
41 | content("c2.center", [Green])
42 | })
43 | content((0,0), [Red])
44 | })
45 |
46 | #test-case({
47 | import draw: *
48 | on-layer(1, none)
49 | on-layer(1, ctx => none)
50 | })
51 |
--------------------------------------------------------------------------------
/tests/line-element-element-intersection/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/line-element-element-intersection/ref.png
--------------------------------------------------------------------------------
/tests/line-element-element-intersection/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/line-element-element-intersection/ref/1.png
--------------------------------------------------------------------------------
/tests/line-element-element-intersection/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let test(a, b, ..line-args) = {
5 | import draw: *
6 |
7 | a; b;
8 | line("a", "b", ..line-args)
9 | }
10 |
11 | #box(stroke: 2pt + red, canvas({
12 | import draw: *
13 |
14 | test(rect((0,-.5), (rel: (1,1)), name: "a"),
15 | circle((3,0), name: "b"))
16 | }))
17 |
18 | #box(stroke: 2pt + red, canvas({
19 | import draw: *
20 |
21 | test(rect((0,-1), (rel: (1,1)), name: "a"),
22 | circle((2,1), name: "b"))
23 | }))
24 |
25 | #box(stroke: 2pt + red, canvas({
26 | import draw: *
27 |
28 | test(rect((0,-2), (rel: (1,1)), name: "a"),
29 | circle((2,2), name: "b"))
30 | }))
31 |
32 | #box(stroke: 2pt + red, canvas({
33 | import draw: *
34 |
35 | test(rect((0,0), (rel: (1,1)), name: "a"),
36 | rect((0,0), (rel: (1,1)), name: "b"))
37 | }))
38 |
39 | #box(stroke: 2pt + red, canvas({
40 | import draw: *
41 |
42 | set-style(content: (padding: .1))
43 | test(content((0,0), [Text], name: "a"),
44 | content((1,1), [Text], name: "b"))
45 | }))
46 |
47 | #box(stroke: 2pt + red, canvas({
48 | import draw: *
49 |
50 | set-style(content: (padding: .1))
51 | test(content((0,0), [Text], frame: "circle", name: "a"),
52 | content((1,1), [Text], frame: "circle", name: "b"))
53 | }))
54 |
55 | #box(stroke: 2pt + red, canvas({
56 | import draw: *
57 |
58 | set-style(content: (padding: .1))
59 | test(rect((0,0), (rel: (1,1)), name: "a"),
60 | group({
61 | line((2,2), (3,1), (rel: (0,2)), (rel: (-.1, -1.6)), close: true)
62 | anchor("default", (5,3))
63 | }, name: "b"))
64 | }))
65 |
--------------------------------------------------------------------------------
/tests/line-fill-rule/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/line-fill-rule/ref/1.png
--------------------------------------------------------------------------------
/tests/line-fill-rule/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 |
3 | #import "/src/lib.typ": *
4 | #import "/tests/helper.typ": *
5 |
6 | #test-case({
7 | import draw: *
8 |
9 | line((25pt, 0pt),
10 | (10pt, 50pt),
11 | (50pt, 20pt),
12 | (0pt, 20pt),
13 | (40pt, 50pt), close: true, fill: blue, fill-rule: "non-zero")
14 | })
15 |
16 | #test-case({
17 | import draw: *
18 |
19 | line((25pt, 0pt),
20 | (10pt, 50pt),
21 | (50pt, 20pt),
22 | (0pt, 20pt),
23 | (40pt, 50pt), close: true, fill: blue, fill-rule: "even-odd")
24 | })
25 |
--------------------------------------------------------------------------------
/tests/local-anchor/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/local-anchor/ref/1.png
--------------------------------------------------------------------------------
/tests/local-anchor/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | circle((0,0), radius: 0.5)
8 | arc((0, 1), start: -90deg, stop: 90deg, name: "c", anchor: "arc-start")
9 | stroke(blue)
10 | circle("c.arc-start", radius: 0.1)
11 | }))
12 |
--------------------------------------------------------------------------------
/tests/mark-anchors/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-anchors/ref/1.png
--------------------------------------------------------------------------------
/tests/mark-anchors/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case(args => {
6 | import draw: *
7 |
8 | line((0, -1), (0, 1))
9 | mark((0, 0), (args.dir,0), symbol: "stealth", anchor: args.anchor)
10 | }, args: (
11 | (dir: +1, anchor: "tip"),
12 | (dir: +1, anchor: "center"),
13 | (dir: +1, anchor: "base"),
14 | (dir: -1, anchor: "tip"),
15 | (dir: -1, anchor: "center"),
16 | (dir: -1, anchor: "base"),
17 | ))
18 |
19 | #test-case(args => {
20 | import draw: *
21 |
22 | line((0, -1), (0, 1), stroke: green)
23 | line((-1, 0), (0,0), mark: (end: "stealth", anchor: args.anchor))
24 | }, args: (
25 | (anchor: "tip"),
26 | (anchor: "center"),
27 | (anchor: "base"),
28 | ))
29 |
30 | #test-case(args => {
31 | import draw: *
32 |
33 | set-style(mark: (stroke: blue))
34 | line((0,-1.2), (0,+1.2), stroke: green)
35 | mark((0, 0), (-1, 0), symbol: args.symbol, anchor: "tip")
36 | line((-1, 2), (3, 2), mark: (start: args.symbol, end: args.symbol, harpoon: true))
37 | }, args: (
38 | (symbol: ">"),
39 | (symbol: "stealth"),
40 | (symbol: "|"),
41 | (symbol: "o"),
42 | (symbol: "]"),
43 | (symbol: "<>"),
44 | (symbol: "[]"),
45 | (symbol: "hook"),
46 | (symbol: "straight"),
47 | (symbol: "barbed"),
48 | (symbol: "+"),
49 | (symbol: "x"),
50 | (symbol: ">"),
51 | ))
52 |
53 | #test-case({
54 | import draw: *
55 |
56 | anchor("a", (-1,0))
57 | anchor("b", (+1,0))
58 |
59 | line("a", "b")
60 | mark("a", "b", symbol: "<", fill: black, anchor: "center")
61 | mark("b", "a", symbol: "<", fill: black, anchor: "center")
62 |
63 | anchor("c", (-1,-1))
64 | anchor("d", (+1,-1))
65 |
66 | line("c", "d")
67 | mark("c", "d", symbol: ">", fill: black, anchor: "center")
68 | mark("d", "c", symbol: ">", fill: black, anchor: "center")
69 | })
70 |
--------------------------------------------------------------------------------
/tests/mark-auto-offset/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-auto-offset/ref/1.png
--------------------------------------------------------------------------------
/tests/mark-auto-offset/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #for w in range(1, 10) {
5 | let w = w / 10
6 | let l = 1
7 | box(stroke: 2pt + red, canvas({
8 | import draw: *
9 |
10 | for x in range(0, 8) {
11 | let width = (x + 1) * 1pt
12 | let x = x * 2
13 |
14 | set-style(stroke: width, mark: (width: w, length: 1, scale: .4, stroke: width))
15 | line((x,0), (x,3), mark: (end: ">", start: ">"))
16 |
17 | line((x - .5,3), (x + .5,3), stroke: .5pt + green)
18 | line((x - .5,0), (x + .5,0), stroke: .5pt + green)
19 | }
20 | for x in range(0, 8) {
21 | let width = (x + 1) * 1pt
22 | let x = x * 2 + 2 * 8
23 |
24 | set-style(stroke: width, mark: (width: w, length: 1, scale: .4, stroke: width + blue))
25 | line((x,0), (x,3), mark: (end: "<", start: "<"))
26 |
27 | line((x - .5,3), (x + .5,3), stroke: .5pt + green)
28 | line((x - .5,0), (x + .5,0), stroke: .5pt + green)
29 | }
30 | }))
31 | par([])
32 | }
33 |
34 | #box(stroke: 2pt + red, canvas({
35 | import draw: *
36 | rect((1,-1), (2,2))
37 | rect((-2,-1), (-1,2))
38 | bezier((-1,-.5), (1,1), (0,-.5), (0,1),
39 | mark: (start: ">", end: ">", fill: blue, stroke: blue, flex: false))
40 | }))
41 |
42 | #box(stroke: 2pt + red, canvas({
43 | import draw: *
44 | rect((1,-1), (2,2))
45 | rect((-2,-1), (-1,2))
46 | bezier((-1,-.5), (1,1), (0,-.5), (0,1),
47 | mark: (start: ">", end: ">", fill: blue, stroke: blue, flex: true))
48 | }))
49 |
50 | #box(stroke: 2pt + red, canvas({
51 | import draw: *
52 | rect((1,-1), (2,2))
53 | rect((-2,-1), (-1,2))
54 | bezier((-1,-.5), (1,1), (0,-.5), (0,1),
55 | mark: (start: "|", end: "o", fill: blue, stroke: blue))
56 | }))
57 |
58 | #box(stroke: 2pt + red, canvas({
59 | import draw: *
60 | rect((1,-1), (2,2))
61 | rect((-2,-1), (-1,2))
62 | catmull((-1,-.5), (0,-.5), (0,1), (1,1),
63 | mark: (start: ">", end: ">", fill: blue, stroke: blue))
64 | }))
65 |
66 | #box(stroke: 2pt + red, canvas({
67 | import draw: *
68 | rect((1,-1), (2,2))
69 | rect((-2,-1), (-1,2))
70 | hobby((-1,-.5), (0,-.5), (0,1), (1,1),
71 | mark: (start: ">", end: ">", fill: blue, stroke: blue))
72 | }))
73 |
--------------------------------------------------------------------------------
/tests/mark-position/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-position/ref/1.png
--------------------------------------------------------------------------------
/tests/mark-position/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | // No Position
6 | #test-case({
7 | import draw: *
8 | set-style(mark: (fill: white))
9 | line((-1,0), (1,0), mark: (start: ">", end: ">"))
10 | })
11 |
12 | // Absolute Position
13 | #test-case({
14 | import draw: *
15 | set-style(mark: (fill: white))
16 | line((-1,1), (1,1), mark: (start: ">", end: ">", pos: .25, shorten-to: none))
17 | })
18 |
19 |
20 | // Relative Offset
21 | #test-case({
22 | import draw: *
23 | set-style(mark: (fill: white))
24 | line((-1,0), (1,0), mark: (start: ">", end: ">", pos: 25%, shorten-to: none))
25 | line((-1,1), (1,1), mark: (end: ">", pos: 50%, shorten-to: none))
26 | line((-1,2), (1,2), mark: (start: ">", pos: 50%, shorten-to: none))
27 | line((-1,3), (1,3), mark: (start: (">", (symbol: "|", pos: 50%, anchor: "center")), end: ">", shorten-to: 0))
28 | })
29 |
--------------------------------------------------------------------------------
/tests/mark-shape-transform/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-shape-transform/ref/1.png
--------------------------------------------------------------------------------
/tests/mark-shape-transform/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import cetz.draw: *
7 |
8 | set-style(mark: (transform-shape: true))
9 |
10 | scale(x: 3)
11 | line((-1,-1), (1,1), mark: (start: "rect", end: "]"))
12 | })
13 |
14 | #test-case({
15 | import cetz.draw: *
16 |
17 | set-style(mark: (transform-shape: false))
18 |
19 | scale(x: 3)
20 | line((-1,-1), (1,1), mark: (start: "rect", end: ">"))
21 | })
22 |
23 | #test-case({
24 | import cetz.draw: *
25 |
26 | set-style(mark: (transform-shape: false))
27 |
28 | rotate(45deg)
29 | line((-1,-1), (1,-1), (1,1), mark: (start: "rect", end: "rect", scale: 3))
30 | })
31 |
--------------------------------------------------------------------------------
/tests/mark-single/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-single/ref.png
--------------------------------------------------------------------------------
/tests/mark-single/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-single/ref/1.png
--------------------------------------------------------------------------------
/tests/mark-single/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | // No Position
6 | #test-case({
7 | import draw: *
8 |
9 | // Left
10 | mark((0,0), (-1,0), symbol: ">", scale: 3, fill: blue)
11 |
12 | // Up
13 | mark((0,0), (0,1), symbol: ">", scale: 3, fill: green)
14 |
15 | // Down
16 | mark((0,0), (0,-1), symbol: ">", scale: 3, fill: red)
17 |
18 | // Right
19 | mark((0,0), (1,0), symbol: ">", scale: 3, fill: yellow)
20 | })
21 |
22 | // Angle
23 | #test-case({
24 | import draw: *
25 |
26 | mark((0,0), 0deg, symbol: ">", scale: 3, fill: blue)
27 | mark((0,0), 90deg, symbol: ">", scale: 3, fill: green)
28 | mark((0,0), 180deg, symbol: ">", scale: 3, fill: red)
29 | mark((0,0), 270deg, symbol: ">", scale: 3, fill: yellow)
30 | })
31 |
--------------------------------------------------------------------------------
/tests/mark-z-axis/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/mark-z-axis/ref/1.png
--------------------------------------------------------------------------------
/tests/mark-z-axis/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | line((-1,0), (1,0), mark: (start: ">", end: ">"))
8 | line((0,-1), (0,1), mark: (start: ">", end: ">"))
9 | line((0,0,-1), (0,0,1), mark: (start: ">", end: ">",
10 | scale: 1))
11 | }))
12 |
--------------------------------------------------------------------------------
/tests/matrix/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/matrix/ref/1.png
--------------------------------------------------------------------------------
/tests/matrix/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": matrix
3 |
4 | #{
5 | let m = (
6 | (3, 2, 1),
7 | (1, 0, 2),
8 | )
9 | let v = (
10 | 1, 0, 4
11 | )
12 | let r = (
13 | 7, 9
14 | )
15 |
16 | assert(matrix.mul-vec(m, v) == r)
17 | }
18 |
--------------------------------------------------------------------------------
/tests/merge/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/merge/ref.png
--------------------------------------------------------------------------------
/tests/merge/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/merge/ref/1.png
--------------------------------------------------------------------------------
/tests/merge/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 |
8 | // Merge lines
9 | fill(red)
10 | merge-path({
11 | line((0,0), (1,2))
12 | line((), (2,0))
13 | line((), (0,0))
14 | }, close: true)
15 |
16 | translate((0, -1))
17 |
18 | // Merge bezier paths
19 | fill(blue)
20 | merge-path({
21 | bezier((0,0), (2,0), (1, 1))
22 | bezier((2, -1), (0, -1), (.5, -2), (1.5, 0))
23 | }, close: true)
24 |
25 | translate((0, -2))
26 |
27 | // Merge different paths
28 | fill(green)
29 | merge-path({
30 | line((0,0), (1,0), (2,-1))
31 | arc((), start: 0deg, stop: -130deg, name: "arc")
32 | bezier("arc.arc-end", (0,0), (0, -1), (2, -2))
33 | })
34 | })
35 |
36 | #test-case({
37 | import draw: *
38 |
39 | rotate(45deg)
40 | merge-path({
41 | line((0,0), (1,0), (2,-1))
42 | arc((), start: 0deg, stop: -130deg, name: "arc")
43 | bezier("arc.arc-end", (0,0), (0, -1), (2, -2))
44 | }, name: "p", fill: yellow)
45 |
46 | for i in range(0, 110, step: 10) {
47 | circle((name: "p", anchor: 1% * i), radius: .1, fill: white)
48 | }
49 | })
50 |
--------------------------------------------------------------------------------
/tests/multiple-marks/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/multiple-marks/ref/1.png
--------------------------------------------------------------------------------
/tests/multiple-marks/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let l = ("|", "o", ">")
6 |
7 | #test-case({
8 | import draw: *
9 |
10 | line((-1, -1), (1, 1), mark: (start: l, end: l))
11 | })
12 |
13 | #test-case({
14 | import draw: *
15 |
16 | bezier((-1, -1), (1, 1), (-1, 1), (1, -1), mark: (start: l, end: l))
17 | })
18 |
19 | #test-case({
20 | import draw: *
21 |
22 | arc((0, 0), start: 0deg, stop: 180deg, anchor: "center", mark: (start: l, end: l))
23 | })
24 |
--------------------------------------------------------------------------------
/tests/padding/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/padding/ref/1.png
--------------------------------------------------------------------------------
/tests/padding/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case(padding: 1, background: gray, {
6 | import draw: *
7 | circle(())
8 | })
9 |
10 | #test-case(padding: (top: 1, left: 2), background: gray, {
11 | import draw: *
12 | scale(x: -1, y: -.5)
13 | circle(())
14 | })
15 |
--------------------------------------------------------------------------------
/tests/palette/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/palette/ref/1.png
--------------------------------------------------------------------------------
/tests/palette/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas(length: 1cm, {
5 | import draw: *
6 |
7 | let p = palette.pink
8 | for i in range(0, p("len")) {
9 | set-style(..p(i))
10 | rect((0,0), (1,1))
11 | set-origin((1,0))
12 | }
13 | }))
14 |
15 | #box(stroke: 2pt + red, canvas(length: 1cm, {
16 | import draw: *
17 |
18 | let p = palette.new(
19 | base: (stroke: (paint: none, dash: "dashed")),
20 | colors: (red, green, blue),
21 | dash: ("solid", "dashed", "dotted"))
22 | for i in range(0, p("len")) {
23 | set-style(..p(i, stroke: true, fill: false))
24 | circle((.5,.5), radius: .5)
25 | set-origin((1,0))
26 | }
27 | }))
28 |
--------------------------------------------------------------------------------
/tests/path-anchors/ref.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/path-anchors/ref.png
--------------------------------------------------------------------------------
/tests/path-anchors/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/path-anchors/ref/1.png
--------------------------------------------------------------------------------
/tests/path-anchors/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let display(body, ..args, angle: false) = {
5 | import draw: *
6 |
7 | // Fixed distance
8 | (body)(..args, name: "elem");
9 | for i in (0, .5, 1) {
10 | circle((name: "elem", anchor: i), radius: .1)
11 | }
12 |
13 | set-origin((3,0))
14 |
15 | (body)(..args, name: "elem");
16 | for i in (0%, 25%, 50%, 75%, 100%) {
17 | circle((name: "elem", anchor: i), radius: .1)
18 | }
19 |
20 | if angle {
21 | set-origin((3,0))
22 |
23 | (body)(..args, name: "elem");
24 | let angles = if args.named().at("mode", default: "") == "OPEN" {
25 | (170deg, 180deg)
26 | } else {
27 | (0deg, 45deg, 90deg, 170deg, 180deg)
28 | }
29 | for i in angles {
30 | circle((name: "elem", anchor: i), radius: .1)
31 | }
32 | }
33 | }
34 |
35 | #box(stroke: 2pt + red, canvas(length: 1cm, {
36 | import draw: *
37 | display(line, (0,0), (.75,1), (1.25,-1), (2,0))
38 | }))
39 |
40 | #box(stroke: 2pt + red, canvas(length: 1cm, {
41 | import draw: *
42 | display(circle, (0,0), angle: true)
43 | }))
44 |
45 | #box(stroke: 2pt + red, canvas(length: 1cm, {
46 | import draw: *
47 | display(circle-through, (-1,0), (0,1), (1,0), angle: true)
48 | }))
49 |
50 | #box(stroke: 2pt + red, canvas(length: 1cm, {
51 | import draw: *
52 | display(arc, (0,0), start: 225deg, stop: 135deg, radius: 2, mode: "OPEN", angle: true)
53 | }))
54 |
55 | #box(stroke: 2pt + red, canvas(length: 1cm, {
56 | import draw: *
57 | display(arc, (0,0), start: 225deg, stop: 135deg, radius: 2, mode: "PIE", angle: true)
58 | }))
59 |
60 | #box(stroke: 2pt + red, canvas(length: 1cm, {
61 | import draw: *
62 | display(arc, (0,0), start: 225deg, stop: 135deg, radius: 2, mode: "CLOSE", angle: true)
63 | }))
64 |
65 | #box(stroke: 2pt + red, canvas(length: 1cm, {
66 | import draw: *
67 | display(line, (-1,0), (0,1), (1,0))
68 | }))
69 |
70 | /*
71 | #box(stroke: 2pt + red, canvas(length: 1cm, {
72 | import draw: *
73 | display(content, (), text(2cm)[Text])
74 | }))
75 | */
76 |
77 | #box(stroke: 2pt + red, canvas(length: 1cm, {
78 | import draw: *
79 | display(rect, (-1,-1), (1,1), angle: true)
80 | }))
81 |
82 | #box(stroke: 2pt + red, canvas(length: 1cm, {
83 | import draw: *
84 | display(rect, (-1,-1), (1,1), radius: .5)
85 | }))
86 |
87 | #box(stroke: 2pt + red, canvas(length: 1cm, {
88 | import draw: *
89 | display(bezier, (-2,0), (2,0), (-1,1), (1,-1))
90 | }))
91 |
92 | #box(stroke: 2pt + red, canvas(length: 1cm, {
93 | import draw: *
94 | display(bezier, (-1,-1), (1,-1), (0,2))
95 | }))
96 |
97 | #box(stroke: 2pt + red, canvas(length: 1cm, {
98 | import draw: *
99 | display(bezier-through, (-1,-1), (0,1), (1,-1))
100 | }))
101 |
102 | #box(stroke: 2pt + red, canvas(length: 1cm, {
103 | import draw: *
104 | display(catmull, (-2,0), (-1,-1), (0,1), (1,-1), (2,0))
105 | }))
106 |
107 | #box(stroke: 2pt + red, canvas(length: 1cm, {
108 | import draw: *
109 | display(group, {
110 | circle((0,0), radius: .5)
111 | circle((1,1), radius: .7)
112 | }, angle: true)
113 | }))
114 |
115 | #box(stroke: 2pt + red, canvas(length: 1cm, {
116 | import draw: *
117 |
118 | rotate(10deg)
119 | rect((-1,-1), (1,1), name: "a")
120 | for i in (0, 1, 2, 3, 4, 5, 6, 7) {
121 | circle((name: "a", anchor: i), radius: .1)
122 | }
123 |
124 | set-origin((3,0))
125 |
126 | rect((-1,-1), (1,1), name: "a")
127 | for i in (0%, 10%, 20%, 30%, 40%, 50%) {
128 | circle((name: "a", anchor: i), radius: .1)
129 | }
130 |
131 | set-origin((3, 0))
132 |
133 | rect((-1,-1), (1,1), name: "a")
134 | for i in range(0, 360, step: 36) {
135 | let i = i * 1deg
136 | circle((name: "a", anchor: i), radius: .1)
137 | }
138 | }))
139 |
--------------------------------------------------------------------------------
/tests/path-decoration/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/path-decoration/ref/1.png
--------------------------------------------------------------------------------
/tests/path-decoration/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #import decorations: zigzag, coil, wave, square
6 |
7 | #let all-fns = (zigzag, coil, wave, square)
8 |
9 | #test-case(fn => {
10 | import draw: *
11 |
12 | fn(line((0,0), (4,0)))
13 | fn(line((0,1), (4,1)), amplitude: .5)
14 | fn(line((0,2), (4,2)), amplitude: t => { 1 - .5 * t / 50% })
15 | fn(line((0,3), (4,3)), amplitude: (0, .5, 1))
16 | }, args: all-fns)
17 |
18 | #test-case(fn => {
19 | import draw: *
20 | fn(hobby((0,0), (4,0), (6,2)))
21 | }, args: all-fns)
22 |
23 | #box(stroke: 2pt + red, canvas(length: 1cm, {
24 | import draw: *
25 |
26 | set-style(radius: .9)
27 | coil(circle((0,0)), amplitude: .2, segments: 30, factor: 100%)
28 | coil(circle((0,2)), amplitude: .2, segments: 30, factor: 120%, stroke: blue)
29 | coil(circle((0,4)), amplitude: .2, segments: 30, factor: 150%, stroke: red)
30 | }))
31 |
32 | #box(stroke: 2pt + red, canvas(length: 1cm, {
33 | import draw: *
34 |
35 | set-style(radius: .9)
36 | wave(circle((0,0)), amplitude: .2, segments: 20, tension: .3)
37 | wave(circle((0,2)), amplitude: .2, segments: 20, tension: .5, stroke: blue)
38 | wave(circle((0,4)), amplitude: .2, segments: 20, tension: 1, stroke: red)
39 | }))
40 |
41 | #box(stroke: 2pt + red, canvas(length: 1cm, {
42 | import draw: *
43 |
44 | set-style(radius: .9)
45 | square(circle((0,2)), amplitude: .2, segments: 20)
46 | }))
47 |
48 | #test-case(fn => {
49 | import draw: *
50 |
51 | fn(line((0,0), (3,0)), start: 10%, stop: 90%, amplitude: .5)
52 | fn(line((0,1), (3,1)), start: 1, stop: 2, amplitude: .5)
53 | }, args: all-fns)
54 |
55 | #test-case(fn => {
56 | import draw: *
57 |
58 | fn(line((0,0,-1), (0,0,1)), start: 10%, stop: 90%)
59 | }, args: all-fns)
60 |
61 | #test-case(factor => {
62 | import draw: *
63 | square(line((0,0), (3,0)), factor: factor)
64 | }, args: (25%, 50%, 75%))
65 |
66 | #test-case({
67 | import draw: *
68 |
69 | // Keep the fixed amplitude
70 | for i in range(0, 6) {
71 | wave(line((0,i), (3,i)), start: 10%, stop: 1 + i / 5,
72 | segment-length: .22, amplitude: .8)
73 | }
74 | })
75 |
76 | #test-case(fn => {
77 | import draw: *
78 |
79 | // Amplitudes of type length
80 | fn(line((0,0), (4,0)), amplitude: 0.25)
81 | fn(line((0,1), (4,1)), amplitude: 2.5mm)
82 | fn(line((0,2), (4,2)), amplitude: t => 1em*calc.sin(float(t)*calc.pi))
83 | fn(line((0,3), (4,3)), amplitude: (5mm, 0, 2mm, 0))
84 | }, args: all-fns)
85 |
86 | // Bug #736: Waves with a single segment
87 | // have are sharp on the second peak.
88 | #test-case({
89 | import draw: *
90 |
91 | wave(line((0,0), (4,0)), segments: 1)
92 | })
93 |
--------------------------------------------------------------------------------
/tests/polygon/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/polygon/ref/1.png
--------------------------------------------------------------------------------
/tests/polygon/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import cetz.draw: *
7 |
8 | polygon((0, 0), 5, radius: 1, name: "poly")
9 |
10 | for-each-anchor("poly", name => {
11 | if name.starts-with(regex("(corner|edge)")) {
12 | circle((), fill: gray, radius: .1)
13 | }
14 | })
15 | })
16 |
17 | #test-case(sides => {
18 | import cetz.draw: *
19 |
20 | polygon((0, 0), sides, radius: 1, angle: 90deg)
21 | }, args: (3, 4, 5, 6))
22 |
23 | #test-case({
24 | import cetz.draw: *
25 |
26 | set-style(polygon: (radius: 1, fill: blue, stroke: red + 4pt))
27 | polygon((0, 0), 6)
28 | })
29 |
30 | #test-case({
31 | import cetz.draw: *
32 |
33 | polygon((0, 0), 6, radius: 1,
34 | fill: red, stroke: blue + 4pt)
35 | })
36 |
37 | #test-case({
38 | import cetz.draw: *
39 |
40 | polygon((0, 0), 5, name: "p1")
41 | polygon((2, 2), 3, name: "p2")
42 | line("p1", "p2")
43 | })
44 |
45 | #test-case({
46 | import cetz.draw: *
47 |
48 | polygon((0, 0), 3, radius: 3cm)
49 | })
50 |
--------------------------------------------------------------------------------
/tests/primitives/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/primitives/ref/1.png
--------------------------------------------------------------------------------
/tests/primitives/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | line((0, 0), (1, 0))
8 | rect((0, 1), (1, 2))
9 | circle((.5, 3.5), radius: .5)
10 | arc((1, 4.5), start: 0deg, stop: 90deg, radius: .5)
11 | bezier((0, 6), (1, 6), (.5, 5))
12 | bezier((0, 7), (1, 7), (.25, 6), (.75, 8))
13 | }))
14 |
--------------------------------------------------------------------------------
/tests/projection-default/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/projection-default/ref/1.png
--------------------------------------------------------------------------------
/tests/projection-default/test.typ:
--------------------------------------------------------------------------------
1 | #import "/src/lib.typ" as cetz
2 | #import "/tests/helper.typ": *
3 | #set page(width: auto, height: auto)
4 |
5 | // Positive direction
6 | #test-case({
7 | import cetz.draw: *
8 |
9 | set-style(mark: (transform-shape: false))
10 | line((0,0,0), (1,0,0), mark: (end: ">"))
11 | line((0,0,0), (0,1,0), mark: (end: ">"))
12 | line((0,0,0), (0,0,1), mark: (end: ">"))
13 | })
14 |
15 | // Negative direction
16 | #test-case({
17 | import cetz.draw: *
18 |
19 | set-style(mark: (transform-shape: false))
20 | line((0,0,0), (-1,0,0), mark: (end: ">"))
21 | line((0,0,0), (0,-1,0), mark: (end: ">"))
22 | line((0,0,0), (0,0,-1), mark: (end: ">"))
23 | })
24 |
--------------------------------------------------------------------------------
/tests/projection-ortho/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/projection-ortho/ref/1.png
--------------------------------------------------------------------------------
/tests/projection-ortho/test.typ:
--------------------------------------------------------------------------------
1 | #import "/src/lib.typ": *
2 | #import "/tests/helper.typ": *
3 | #set page(width: auto, height: auto)
4 |
5 | #let axes(l) = {
6 | import draw: *
7 |
8 | set-style(mark: (end: ">"))
9 |
10 | on-layer(-1, {
11 | line((-l,0), (l,0), stroke: red, name: "x")
12 | content((rel: ((name: "x", anchor: 50%), .5, "x.end"), to: "x.end"), text(red, $x$))
13 |
14 | line((0,-l), (0,l), stroke: blue, name: "y")
15 | content((rel: ((name: "y", anchor: 50%), .5, "y.end"), to: "y.end"), text(blue, $y$))
16 |
17 | line((0,0,-l), (0,0,l), stroke: green, name: "z", mark: (z-up: (1,0,0)))
18 | content((rel: ((name: "z", anchor: 50%), .5, "z.end"), to: "z.end"), text(green, $z$))
19 | })
20 | }
21 |
22 | #let checkerboard() = {
23 | import draw: *
24 | for x in range(0, 3) {
25 | for y in range(0, 3) {
26 | rect((x,y),(rel: (1,1)),
27 | fill: if calc.rem(x + y, 2) != 0 { black } else { white })
28 | }
29 | }
30 | }
31 |
32 | #test-case({
33 | import draw: *
34 | ortho(reset-transform: false, {
35 | line((-1, 0), (1, 0), mark: (end: ">"))
36 | })
37 | })
38 |
39 | #test-case({
40 | import draw: *
41 | ortho({
42 | axes(4)
43 | checkerboard() // Same as on-xy
44 | })
45 | })
46 |
47 | #test-case({
48 | import draw: *
49 | ortho({
50 | axes(4)
51 | on-xy({
52 | checkerboard()
53 | })
54 | })
55 | })
56 |
57 | #test-case({
58 | import draw: *
59 | ortho({
60 | axes(4)
61 | on-xz({
62 | checkerboard()
63 | })
64 | })
65 | })
66 |
67 | #test-case({
68 | import draw: *
69 | ortho({
70 | axes(4)
71 | on-yz({
72 | checkerboard()
73 | })
74 | })
75 | })
76 |
77 | #test-case({
78 | import draw: *
79 | ortho(sorted: true, {
80 | axes(4)
81 | on-yz(x: -1, {
82 | checkerboard()
83 | })
84 | on-xy(z: -1, {
85 | checkerboard()
86 | })
87 | on-xz(y: -1, {
88 | checkerboard()
89 | })
90 | })
91 | })
92 |
93 | // Ordering
94 | #test-case({
95 | import draw: *
96 | ortho(sorted: true, {
97 | scope({ translate((0, 0, +1)); rect((-1, -1), (1, 1), fill: blue) })
98 | scope({ translate((0, 0, 0)); rect((-1, -1), (1, 1), fill: red) })
99 | scope({ translate((0, 0, -1)); rect((-1, -1), (1, 1), fill: green) })
100 | })
101 | })
102 |
103 | // Fully visible
104 | #test-case({
105 | import draw: *
106 | ortho(x: 0deg, y: 0deg, cull-face: "cw", {
107 | rect((-1, -1), (1, 1))
108 | circle((0,0))
109 | })
110 | })
111 |
112 | // Nothing visible
113 | #test-case({
114 | import draw: *
115 | ortho(x: 0deg, y: 0deg, cull-face: "cw", {
116 | line((-1, -1), (1, -1), (1, 1), (-1, 1), close: true)
117 | rotate(y: 120deg)
118 | line((-1,-1), (1,-1), (0,1), close: true)
119 | })
120 | })
121 |
122 | // Face order of library shapes
123 | #test-case({
124 | import draw: *
125 | ortho(cull-face: "cw", {
126 | rect((-1, -1), (1, 1), radius: .5)
127 | })
128 | })
129 |
130 | #test-case({
131 | import draw: *
132 | ortho(cull-face: "cw", {
133 | circle((0,0))
134 | })
135 | })
136 |
137 | #test-case({
138 | import draw: *
139 | ortho(cull-face: "cw", {
140 | arc((0,0), start: 0deg, stop: 270deg, mode: "PIE")
141 | })
142 | })
143 |
144 | #test-case({
145 | import draw: *
146 | ortho(cull-face: "cw", {
147 | content((0,0), [Text])
148 | })
149 | })
150 |
--------------------------------------------------------------------------------
/tests/rect-rounded/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/rect-rounded/ref/1.png
--------------------------------------------------------------------------------
/tests/rect-rounded/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #let test(..args) = {
5 | import draw: *
6 | rect(..args, name: "r")
7 | for-each-anchor("r", n => {
8 | circle("r." + n, radius: .05, fill: gray)
9 | })
10 | }
11 |
12 | #box(stroke: 2pt + red, canvas({
13 | import draw: *
14 |
15 | test((-1,-1), (1,1))
16 | }))
17 |
18 | #box(stroke: 2pt + red, canvas({
19 | import draw: *
20 |
21 | test((-1,-1), (1,1), radius: 0)
22 | set-origin((2.5, 0))
23 | test((-1,-1), (1,1), radius: .5)
24 | set-origin((2.5, 0))
25 | test((-1,-1), (1,1), radius: 1)
26 | }))
27 |
28 | #box(stroke: 2pt + red, canvas({
29 | import draw: *
30 |
31 | test((-1,-1), (1,1), radius: (north: 1))
32 | set-origin((2.5, 0))
33 | test((-1,-1), (1,1), radius: (east: 1))
34 | set-origin((2.5, 0))
35 | test((-1,-1), (1,1), radius: (south: 1))
36 | set-origin((2.5, 0))
37 | test((-1,-1), (1,1), radius: (west: 1))
38 | }))
39 |
40 | #box(stroke: 2pt + red, canvas({
41 | import draw: *
42 |
43 | test((-1,-1), (1,1), radius: (north-west: 1))
44 | set-origin((2.5, 0))
45 | test((-1,-1), (1,1), radius: (north-east: 1))
46 | set-origin((2.5, 0))
47 | test((-1,-1), (1,1), radius: (south-east: 1))
48 | set-origin((2.5, 0))
49 | test((-1,-1), (1,1), radius: (south-west: 1))
50 | }))
51 |
52 | #box(stroke: 2pt + red, canvas({
53 | import draw: *
54 |
55 | test((-1,-1), (1,1), radius: (north-west: 1, north-east: .5,
56 | south-west: .25, rest: 0.1))
57 | }))
58 |
59 | // Use ratio values
60 | #box(stroke: 2pt + red, canvas({
61 | import draw: *
62 |
63 | test((-1,-1), (3,1), radius: (north-west: 50%, north-east: 25%,
64 | south-west: 10%, rest: 0))
65 | }))
66 |
67 | // Use different x & y radii
68 | #box(stroke: 2pt + red, canvas({
69 | import draw: *
70 |
71 | test((-1,-1), (3,1), radius: (north-west: (50%, .2), south-east: (50%, .2)))
72 | }))
73 |
74 | // Use fixed length values
75 | #box(stroke: 2pt + red, canvas({
76 | import draw: *
77 |
78 | test((-1,-1), (3,1), radius: .5cm)
79 | }))
80 |
--------------------------------------------------------------------------------
/tests/rect/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/rect/ref/1.png
--------------------------------------------------------------------------------
/tests/rect/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | rect((1,1), (0,0), name: "r")
8 | circle("r.center", radius: .1)
9 | circle("r.north", fill: red, radius: .1)
10 | circle("r.south", fill: green, radius: .1)
11 | circle("r.west", fill: blue, radius: .1)
12 | circle("r.east", fill: yellow, radius: .1)
13 | }))
14 |
--------------------------------------------------------------------------------
/tests/relative-length/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/relative-length/ref/1.png
--------------------------------------------------------------------------------
/tests/relative-length/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #set text(10pt)
5 | #box(stroke: 2pt + red, canvas(length: 1em, {
6 | import draw: *
7 |
8 | content((0,0), [M])
9 | content((1,0), [M])
10 | content((0,1), [M])
11 | }))
12 |
13 | #set text(20pt)
14 | #box(stroke: 2pt + red, canvas(length: 1em, {
15 | import draw: *
16 |
17 | content((0,0), [M])
18 | content((1,0), [M])
19 | content((0,1), [M])
20 | }))
21 |
--------------------------------------------------------------------------------
/tests/relative-no-update/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/relative-no-update/ref/1.png
--------------------------------------------------------------------------------
/tests/relative-no-update/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 | circle((0, 0), stroke: blue)
7 | circle((rel: (0, -1), update: false), stroke: red)
8 | circle((rel: (0, -2)), stroke: green)
9 | }))
10 |
--------------------------------------------------------------------------------
/tests/right-angle/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/right-angle/ref/1.png
--------------------------------------------------------------------------------
/tests/right-angle/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let angles = (0, 90, 180, 270, 45, 135).map(v => v * 1deg)
6 |
7 | #test-case(a => {
8 | import draw: *
9 | import angle: right-angle
10 |
11 | let (o, a, b) = (
12 | (0,0),
13 | ((0, 0), 100%, a, (1, 0)),
14 | ((0, 0), 100%, a + 90deg, (1, 0)),
15 | )
16 |
17 | line(a, o, b)
18 | right-angle(o, a, b)
19 | }, args: angles)
20 |
21 | #test-case(a => {
22 | import draw: *
23 | import angle: right-angle
24 |
25 | let (o, a, b) = (
26 | (0,0),
27 | ((0, 0), 100%, a, (1, 0)),
28 | ((0, 0), 100%, a + 45deg, (1, 0)),
29 | )
30 |
31 | line(a, o, b)
32 | right-angle(o, a, b)
33 | }, args: angles)
34 |
35 | #test-case(a => {
36 | import draw: *
37 | import angle: right-angle
38 |
39 | let (o, a, b) = (
40 | (0,0),
41 | ((0, 0), 100%, a, (1, 0)),
42 | ((0, 0), 100%, a + 135deg, (1, 0)),
43 | )
44 |
45 | line(a, o, b)
46 | right-angle(o, a, b)
47 | }, args: angles)
48 |
49 | #test-case({
50 | import draw: *
51 | import angle: right-angle
52 |
53 | let (o, a, b) = ((0,0), (0,1), (1,0))
54 | line(a, o, b)
55 | right-angle(o, a, b, name: "angle")
56 | for-each-anchor("angle", n => {
57 | if n in ("a", "b", "origin", "corner", "label") {
58 | circle("angle." + n, stroke: blue, radius: .1)
59 | }
60 | })
61 | })
62 |
63 | // Bug #571
64 | #test-case({
65 | import draw: *
66 | import angle: right-angle
67 |
68 | let (o, a, b) = ((0,3), (0,4), (1,3))
69 | line(a, o, b)
70 | right-angle(o, a, b, name: "angle")
71 | })
72 |
--------------------------------------------------------------------------------
/tests/ring/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/ring/ref/1.png
--------------------------------------------------------------------------------
/tests/ring/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | let ring(start, end, radius) = merge-path({
8 | arc((0, 0), start: start, stop: end, radius: radius,
9 | anchor: "origin", name: "outer")
10 |
11 | arc("outer.origin", start: end, delta: -(end - start), radius: radius - .2,
12 | anchor: "origin", name: "inner")
13 |
14 | // line("outer.end", "inner.start")
15 | }, close: true)
16 |
17 | stroke(black)
18 | fill(blue)
19 | for i in range(0, 6) {
20 | ring((i+1) * 40deg, (i+1) * 40deg + 120deg, 2 - i * .3)
21 | }
22 | }))
23 |
--------------------------------------------------------------------------------
/tests/root-anchor/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/root-anchor/ref/1.png
--------------------------------------------------------------------------------
/tests/root-anchor/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import draw: *
7 |
8 | anchor("test", (1, 1))
9 | circle((1,1))
10 |
11 | translate((3,1))
12 | circle("test", radius: .5, stroke: green)
13 | circle((1,1), radius: .5, stroke: red)
14 | })
15 |
--------------------------------------------------------------------------------
/tests/rotate-around/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/rotate-around/ref/1.png
--------------------------------------------------------------------------------
/tests/rotate-around/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let draw-shapes() = {
6 | import draw: *
7 |
8 | rect((-2,-2), (-1,-1))
9 | circle((-1.5,1.5), radius: .5)
10 | line((1,1), (1.5,2), (2,1), close: true)
11 | }
12 |
13 | #test-case({
14 | import draw: *
15 | grid((-3,-3), (3,3))
16 |
17 | set-style(fill: gray)
18 | draw-shapes()
19 |
20 | rotate(45deg, origin: (0,0))
21 | set-style(fill: blue)
22 | draw-shapes()
23 | })
24 |
25 | #test-case({
26 | import draw: *
27 | grid((-3,-3), (3,5))
28 |
29 | set-style(fill: gray)
30 | draw-shapes()
31 |
32 | rotate(45deg, origin: (-1.5,1.5))
33 | set-style(fill: blue)
34 | draw-shapes()
35 | })
36 |
37 | #test-case({
38 | import draw: *
39 | grid((-5,-5), (1,1))
40 |
41 | scale(2, origin: (-2,-2))
42 | set-style(fill: blue)
43 | rect((-3,-3), (rel: (1,1)))
44 | rect((-2,-3), (rel: (1,1)))
45 | rect((-2,-2), (rel: (1,1)))
46 | rect((-3,-2), (rel: (1,1)))
47 | })
48 |
49 | #test-case({
50 | import draw: *
51 | grid((-4,-4), (2,2))
52 |
53 | set-style(fill: gray)
54 | rect((-3,-3), (rel: (2,2)))
55 |
56 | rotate(45deg, origin: (-2,-2))
57 | scale(.5, origin: (-2,-2))
58 | set-style(fill: blue)
59 | rect((-3,-3), (rel: (2,2)))
60 | })
61 |
62 | #test-case({
63 | import draw: *
64 | grid((-4,-4), (2,2))
65 |
66 | set-transform(none)
67 | scale(y: -1)
68 |
69 | set-style(fill: gray)
70 | rect((-3,-3), (rel: (2,2)))
71 |
72 | rotate(x: 60deg, y: 45deg, origin: (-2,-2))
73 | set-style(fill: blue)
74 | rect((-3,-3), (rel: (2,2)))
75 | })
76 |
--------------------------------------------------------------------------------
/tests/rotation/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/rotation/ref/1.png
--------------------------------------------------------------------------------
/tests/rotation/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | group(name: "g", {
8 | translate((-.5, .5, 0))
9 |
10 | // CCW
11 | rotate(30deg)
12 |
13 | rect((0, 0), (1, 1), name: "r")
14 | anchor("1", "r.north-west")
15 | anchor("2", "r.north-east")
16 | anchor("3", "r.south-west")
17 | anchor("4", "r.south-east")
18 | })
19 |
20 | stroke(green)
21 | circle("g.1", radius: .1)
22 | circle("g.2", radius: .1)
23 | circle("g.3", radius: .1)
24 | circle("g.4", radius: .1)
25 | }))
26 |
27 | #let draw-xyz() = {
28 | import draw: *
29 | line((-1,0), (1,0), stroke: red)
30 | line((0,-1), (0,1), stroke: blue)
31 | line((0,0,-1), (0,0,1), stroke: green)
32 | }
33 |
34 | #box(stroke: 2pt + red, canvas({
35 | import draw: *
36 |
37 | set-transform(none)
38 | rotate(z: 45deg)
39 | draw-xyz()
40 | }))
41 | #box(stroke: 2pt + red, canvas({
42 | import draw: *
43 |
44 | set-transform(none)
45 | rotate(x: 45deg)
46 | draw-xyz()
47 | }))
48 | #box(stroke: 2pt + red, canvas({
49 | import draw: *
50 |
51 | set-transform(none)
52 | rotate(y: 45deg)
53 | draw-xyz()
54 | }))
55 |
56 | #box(stroke: 2pt + red, canvas({
57 | import draw: *
58 |
59 | set-transform(none)
60 | rotate(yaw: 45deg)
61 | draw-xyz()
62 | }))
63 | #box(stroke: 2pt + red, canvas({
64 | import draw: *
65 |
66 | set-transform(none)
67 | rotate(pitch: 45deg)
68 | draw-xyz()
69 | }))
70 | #box(stroke: 2pt + red, canvas({
71 | import draw: *
72 |
73 | set-transform(none)
74 | rotate(roll: 45deg)
75 | draw-xyz()
76 | }))
77 |
--------------------------------------------------------------------------------
/tests/set-get-ctx/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/set-get-ctx/ref/1.png
--------------------------------------------------------------------------------
/tests/set-get-ctx/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas(length: 1cm, {
5 | import draw: *
6 | set-ctx(ctx => {
7 | ctx.my-custom-attribute = "123"
8 | return ctx
9 | })
10 |
11 | get-ctx(ctx => {
12 | set-style(stroke: green)
13 | content((0, 0), ctx.my-custom-attribute, frame: "rect")
14 | })
15 |
16 | // Note that the set-style is _not_ scoped!
17 | circle((0,0))
18 | }))
19 |
--------------------------------------------------------------------------------
/tests/style/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/style/ref/1.png
--------------------------------------------------------------------------------
/tests/style/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | let next(body) = {
8 | translate((0,-.2,0))
9 | group(body)
10 | }
11 |
12 | next({
13 | line((0,0), (1,0))
14 | })
15 | next({
16 | set-style(stroke: blue)
17 | line((0,0), (1,0))
18 | })
19 | next({
20 | line((0,0), (1,0), stroke: blue)
21 | })
22 | next({
23 | // Blue arrow
24 | set-style(stroke: blue)
25 | line((0,0), (1,0), mark: (end: ">"))
26 | })
27 | next({
28 | // Blue arrow
29 | line((0,0), (1,0), mark: (end: ">"), stroke: blue)
30 | })
31 | next({
32 | // Blue + Green arrow head
33 | line((0,0), (1,0), mark: (end: ">", stroke: green), stroke: blue)
34 | })
35 | next({
36 | // Blue + Yellow arrow head
37 | set-style(mark: (stroke: yellow))
38 | line((0,0), (1,0), mark: (end: ">"), stroke: blue)
39 | })
40 | next({
41 | // Blue + Green arrow head
42 | set-style(mark: (stroke: yellow), stroke: red)
43 | line((0,0), (1,0), mark: (end: ">", stroke: green), stroke: blue)
44 | })
45 | next({
46 | // Blue + Yellow/Green arrow head
47 | set-style(mark: (stroke: yellow, fill: auto), stroke: blue, fill: blue)
48 | line((0,0), (1,0), mark: (end: ">"), fill: green, stroke: green)
49 | })
50 | next({
51 | // Blue arrow
52 | set-style(stroke: red)
53 | line((0,0), (1,0), mark: (end: ">"), stroke: blue)
54 | })
55 | }))
56 |
57 |
--------------------------------------------------------------------------------
/tests/transform-precission/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/transform-precission/ref/1.png
--------------------------------------------------------------------------------
/tests/transform-precission/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #test-case({
6 | import cetz.draw: *
7 | for i in range(0, 90 + 1) {
8 | rotate(22deg)
9 | translate((0,1))
10 | rotate(-25deg)
11 | translate((0,-1))
12 | scale(y: -1)
13 | }
14 |
15 | // With rounding errors, the line and decoration
16 | // won't be at the same location.
17 | line((-1,0), (1,0), stroke: red)
18 |
19 | cetz.decorations.wave(line((-1,0), (1,0), stroke: green))
20 | })
21 |
22 | // #580
23 | #test-case({
24 | import cetz.draw: *
25 | for i in range(0, 360, step: 3) {
26 | let th = 1deg * i
27 | set-ctx(ctx => {
28 | ctx.transform = ((calc.cos(th), -calc.sin(th), 0, 0),
29 | (-calc.sin(th), -calc.cos(th), 0, 0),
30 | (0, 0, 1, 0),
31 | (0, 0, 0, 1),)
32 | return ctx
33 | })
34 |
35 | circle((0deg, 4), radius: 0.1, name: "X", fill: luma(200))
36 | line("X", (rel: (1,0)))
37 | }
38 | })
39 |
--------------------------------------------------------------------------------
/tests/translation/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/translation/ref/1.png
--------------------------------------------------------------------------------
/tests/translation/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | group(name: "g", {
8 | translate((-1.5, .5, 0))
9 |
10 | rect((0, 0), (1, 1))
11 | anchor("tl", (0, 0))
12 | anchor("tr", (1, 0))
13 | anchor("bl", (0, 1))
14 | anchor("br", (1, 1))
15 | })
16 |
17 | group({
18 | line((-2, 0), (2, 0))
19 | line((0, -2), (0, 2))
20 | })
21 |
22 | stroke(green)
23 | circle("g.tl", radius: .1)
24 | circle("g.tr", radius: .1)
25 | circle("g.bl", radius: .1)
26 | circle("g.br", radius: .1)
27 | }))
28 |
29 | #box(stroke: 2pt + red, canvas({
30 | import draw: *
31 |
32 | rect((0, 0), (1, 1), name: "a", fill: blue)
33 | content("a.center", [A])
34 |
35 | // The translation must not get scaled to 2,
36 | // the rects have to touch at the edge.
37 | group({
38 | translate((0, 1))
39 | scale(2)
40 | rect((0, 0), (1, 1), name: "b", fill: green)
41 | content("b.center", [B])
42 | })
43 |
44 | // Translation should get scaled if multiplied post
45 | // scaling.
46 | group({
47 | scale(2)
48 | translate((.5, 0), pre: false)
49 | rect((0, 0), (.5, .5), name: "c", fill: red)
50 | content("c.center", [C])
51 | })
52 | }))
53 |
--------------------------------------------------------------------------------
/tests/tree/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/tree/ref/1.png
--------------------------------------------------------------------------------
/tests/tree/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 | #import "/tests/helper.typ": *
4 |
5 | #let data = (
6 | [A], ([B], [C], [D]), ([E], [F])
7 | )
8 |
9 | #test-case({
10 | import draw: *
11 | import tree: *
12 |
13 | set-style(
14 | mark: (fill: auto),
15 | content: (padding: .2),
16 | fill: gray.lighten(70%),
17 | stroke: gray.lighten(70%))
18 |
19 | tree(data, spread: 2.5, grow: 2, draw-node: (node, ..) => {
20 | content((), node.content, frame: "circle")
21 | }, draw-edge: (from, to, ..) => {
22 | line(from, to, mark: (start: "stealth", end: "stealth"))
23 | }, name: "tree")
24 |
25 | // Draw a "custom" connection between two nodes
26 | let (a, b) = ("tree.0-0-1", "tree.0-1-0",)
27 | line((a, .6, b), (b, .6, a), mark: (end: ">", start: ">"))
28 | })
29 |
30 | #for position in ("begin", "center", "end") {
31 | test-case({
32 | cetz.draw.set-style(content: (frame: "rect", padding: .1))
33 | cetz.tree.tree(data, parent-position: position)
34 | })
35 | h(.1cm)
36 | }
37 |
38 | #for direction in ("down", "up", "left", "right") {
39 | test-case({
40 | cetz.draw.set-style(content: (frame: "rect", padding: .1))
41 | cetz.tree.tree(data, direction: direction)
42 | })
43 | h(.1cm)
44 | }
45 |
46 | #test-case(edge-layer => {
47 | import cetz.draw: *
48 | cetz.tree.tree(data, edge-layer: edge-layer, draw-node: (node, ..) => {
49 | circle((), radius: .3, fill: white)
50 | content((), node.content)
51 | }, draw-edge: (from, to, ..) => {
52 | line((anchor: "center", name: from),
53 | (anchor: "center", name: to), stroke: red + 2pt)
54 | })
55 | }, args: (0, 1))
56 |
--------------------------------------------------------------------------------
/tests/viewport/ref/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cetz-package/cetz/6528b5316306c1fcda33637584a24b9e66b5a2cc/tests/viewport/ref/1.png
--------------------------------------------------------------------------------
/tests/viewport/test.typ:
--------------------------------------------------------------------------------
1 | #set page(width: auto, height: auto)
2 | #import "/src/lib.typ": *
3 |
4 | #box(stroke: 2pt + red, canvas({
5 | import draw: *
6 |
7 | let vp(from, to, bounds: (1,1,1)) = {
8 | group(name: "r", {
9 | rect(from, to)
10 | anchor("from", from)
11 | anchor("to", to)
12 | })
13 | group({
14 | set-viewport("r.from", "r.to", bounds: bounds)
15 | content((0,0), [A])
16 | content((1,0), [B])
17 | content((1,1), [C])
18 | content((0,1), [D])
19 | })
20 | }
21 |
22 | // Mark (0,0)
23 | line((-1,0),(1,0), stroke: blue)
24 | line((0,-1),(0,1), stroke: blue)
25 |
26 | group({
27 | translate(x: -1)
28 | rotate(45deg)
29 | rect((1,1), (4,4))
30 | set-viewport((1,1), (4,4))
31 | for i in range(0, 4) {
32 | for j in range(0, 4) {
33 | circle((i / 3, j / 3), radius: .1, fill: (red, green, blue).at(calc.rem(i+j, 3)))
34 | }
35 | }
36 | })
37 |
38 | group({
39 | translate((-2.5,-2.5))
40 | vp((2,2), (3,3))
41 | })
42 |
43 | vp((4,8), (1,5), bounds: (1,1,0)) // Mirrored edges
44 | vp((2,6), (3,7), bounds: (2,2,0)) // Non 1 bounds
45 | }))
46 |
--------------------------------------------------------------------------------
/typst.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "cetz"
3 | version = "0.3.4"
4 | compiler = "0.13.0"
5 | repository = "https://github.com/cetz-package/cetz"
6 | homepage = "https://cetz-package.github.io/"
7 | entrypoint = "src/lib.typ"
8 | authors = [
9 | "Johannes Wolf ",
10 | "fenjalien "
11 | ]
12 | categories = [ "visualization" ]
13 | license = "LGPL-3.0-or-later"
14 | description = "Drawing with Typst made easy, providing an API inspired by TikZ and Processing. Includes modules for plotting, charts and tree layout."
15 | keywords = [ "draw", "canvas", "tree" ]
16 | exclude = [ "/gallery/*", "manual.pdf", "manual.typ" ]
17 |
--------------------------------------------------------------------------------