summaryrefslogtreecommitdiff
path: root/library/src/math/cancel.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/src/math/cancel.rs')
-rw-r--r--library/src/math/cancel.rs187
1 files changed, 0 insertions, 187 deletions
diff --git a/library/src/math/cancel.rs b/library/src/math/cancel.rs
deleted file mode 100644
index f576a727..00000000
--- a/library/src/math/cancel.rs
+++ /dev/null
@@ -1,187 +0,0 @@
-use super::*;
-
-/// Displays a diagonal line over a part of an equation.
-///
-/// This is commonly used to show the elimination of a term.
-///
-/// ## Example { #example }
-/// ```example
-/// >>> #set page(width: 140pt)
-/// Here, we can simplify:
-/// $ (a dot b dot cancel(x)) /
-/// cancel(x) $
-/// ```
-///
-/// Display: Cancel
-/// Category: math
-#[element(LayoutMath)]
-pub struct CancelElem {
- /// The content over which the line should be placed.
- #[required]
- pub body: Content,
-
- /// The length of the line, relative to the length of the diagonal spanning
- /// the whole element being "cancelled". A value of `{100%}` would then have
- /// the line span precisely the element's diagonal.
- ///
- /// ```example
- /// >>> #set page(width: 140pt)
- /// $ a + cancel(x, length: #200%)
- /// - cancel(x, length: #200%) $
- /// ```
- #[default(Rel::new(Ratio::one(), Abs::pt(3.0).into()))]
- pub length: Rel<Length>,
-
- /// If the cancel line should be inverted (pointing to the top left instead
- /// of top right).
- ///
- /// ```example
- /// >>> #set page(width: 140pt)
- /// $ (a cancel((b + c), inverted: #true)) /
- /// cancel(b + c, inverted: #true) $
- /// ```
- #[default(false)]
- pub inverted: bool,
-
- /// If two opposing cancel lines should be drawn, forming a cross over the
- /// element. Overrides `inverted`.
- ///
- /// ```example
- /// >>> #set page(width: 140pt)
- /// $ cancel(Pi, cross: #true) $
- /// ```
- #[default(false)]
- pub cross: bool,
-
- /// How to rotate the cancel line. See the [line's
- /// documentation]($func/line.angle) for more details.
- ///
- /// ```example
- /// >>> #set page(width: 140pt)
- /// $ cancel(Pi, rotation: #30deg) $
- /// ```
- #[default(Angle::zero())]
- pub rotation: Angle,
-
- /// How to stroke the cancel line. See the
- /// [line's documentation]($func/line.stroke) for more details.
- ///
- /// ```example
- /// >>> #set page(width: 140pt)
- /// $ cancel(
- /// sum x,
- /// stroke: #(
- /// paint: red,
- /// thickness: 1.5pt,
- /// dash: "dashed",
- /// ),
- /// ) $
- /// ```
- #[resolve]
- #[fold]
- #[default(PartialStroke {
- // Default stroke has 0.5pt for better visuals.
- thickness: Smart::Custom(Abs::pt(0.5)),
- ..Default::default()
- })]
- pub stroke: PartialStroke,
-}
-
-impl LayoutMath for CancelElem {
- fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
- let body = ctx.layout_fragment(&self.body())?;
- // Use the same math class as the body, in order to preserve automatic spacing around it.
- let body_class = body.class().unwrap_or(MathClass::Special);
- let mut body = body.into_frame();
-
- let styles = ctx.styles();
- let body_size = body.size();
- let span = self.span();
- let length = self.length(styles).resolve(styles);
-
- let stroke = self.stroke(styles).unwrap_or(Stroke {
- paint: TextElem::fill_in(styles),
- ..Default::default()
- });
-
- let invert = self.inverted(styles);
- let cross = self.cross(styles);
- let angle = self.rotation(styles);
-
- let invert_first_line = !cross && invert;
- let first_line = draw_cancel_line(
- length,
- stroke.clone(),
- invert_first_line,
- angle,
- body_size,
- span,
- );
-
- // The origin of our line is the very middle of the element.
- let center = body_size.to_point() / 2.0;
- body.push_frame(center, first_line);
-
- if cross {
- // Draw the second line.
- let second_line =
- draw_cancel_line(length, stroke, true, angle, body_size, span);
-
- body.push_frame(center, second_line);
- }
-
- ctx.push(FrameFragment::new(ctx, body).with_class(body_class));
-
- Ok(())
- }
-}
-
-/// Draws a cancel line.
-fn draw_cancel_line(
- length: Rel<Abs>,
- stroke: Stroke,
- invert: bool,
- angle: Angle,
- body_size: Size,
- span: Span,
-) -> Frame {
- // B
- // /|
- // diagonal / | height
- // / |
- // / |
- // O ----
- // width
- let diagonal = body_size.to_point().hypot();
- let length = length.relative_to(diagonal);
- let (width, height) = (body_size.x, body_size.y);
- let mid = body_size / 2.0;
-
- // Scale the amount needed such that the cancel line has the given 'length'
- // (reference length, or 100%, is the whole diagonal).
- // Scales from the center.
- let scale = length.to_raw() / diagonal.to_raw();
-
- // invert horizontally if 'invert' was given
- let scale_x = scale * if invert { -1.0 } else { 1.0 };
- let scale_y = scale;
- let scales = Axes::new(scale_x, scale_y);
-
- // Draw a line from bottom left to top right of the given element, where the
- // origin represents the very middle of that element, that is, a line from
- // (-width / 2, height / 2) with length components (width, -height) (sign is
- // inverted in the y-axis). After applying the scale, the line will have the
- // correct length and orientation (inverted if needed).
- let start = Axes::new(-mid.x, mid.y).zip(scales).map(|(l, s)| l * s);
- let delta = Axes::new(width, -height).zip(scales).map(|(l, s)| l * s);
-
- let mut frame = Frame::new(body_size);
- frame.push(
- start.to_point(),
- FrameItem::Shape(Geometry::Line(delta.to_point()).stroked(stroke), span),
- );
-
- // Having the middle of the line at the origin is convenient here.
- frame.transform(Transform::rotate(angle));
- frame
-}