This commit is contained in:
Martin Haug 2022-03-16 12:36:50 +01:00
parent 288a926fea
commit 4d617bcd67
7 changed files with 138 additions and 0 deletions

View File

@ -40,6 +40,16 @@ impl Angle {
(self.0).0
}
/// Get the sine of this angle.
pub fn sin(self) -> f64 {
self.to_rad().sin()
}
/// Get the cosine of this angle.
pub fn cos(self) -> f64 {
self.to_rad().cos()
}
/// Create an angle from a value in a unit.
pub fn with_unit(val: f64, unit: AngularUnit) -> Self {
Self(Scalar(val * unit.raw_scale()))

View File

@ -49,6 +49,12 @@ impl Point {
}
}
impl From<Spec<Length>> for Point {
fn from(spec: Spec<Length>) -> Self {
Self::new(spec.x, spec.y)
}
}
impl Get<SpecAxis> for Point {
type Component = Length;

View File

@ -0,0 +1,61 @@
use crate::library::prelude::*;
/// Display a line without affecting the layout.
#[derive(Debug, Hash)]
pub struct LineNode(Spec<Linear>, Spec<Linear>);
#[node]
impl LineNode {
/// How the stroke the line.
pub const STROKE: Smart<Paint> = Smart::Auto;
/// The line's thickness.
pub const THICKNESS: Length = Length::pt(1.0);
fn construct(_: &mut Context, args: &mut Args) -> TypResult<Content> {
let origin = args.named::<Spec<Linear>>("origin")?.unwrap_or_default();
let to = match args.named::<Spec<Linear>>("to")? {
Some(to) => to.zip(origin).map(|(to, from)| to - from),
None => {
let length =
args.named::<Linear>("length")?.unwrap_or(Length::cm(1.0).into());
let angle = args.named::<Angle>("angle")?.unwrap_or_default();
let x = angle.cos() * length;
let y = angle.sin() * length;
Spec::new(x, y)
}
};
Ok(Content::inline(Self(origin, to)))
}
}
impl Layout for LineNode {
fn layout(
&self,
_: &mut Context,
regions: &Regions,
styles: StyleChain,
) -> TypResult<Vec<Arc<Frame>>> {
let target = regions.expand.select(regions.first, Size::zero());
let mut frame = Frame::new(target);
let thickness = styles.get(Self::THICKNESS);
let stroke = Some(Stroke {
paint: styles.get(Self::STROKE).unwrap_or(Color::BLACK.into()),
thickness,
});
let resolved_origin =
self.0.zip(regions.base).map(|(l, b)| Linear::resolve(l, b));
let resolved_to = self.1.zip(regions.base).map(|(l, b)| Linear::resolve(l, b));
let geometry = Geometry::Line(resolved_to.into());
let shape = Shape { geometry, fill: None, stroke };
frame.prepend(resolved_origin.into(), Element::Shape(shape));
Ok(vec![Arc::new(frame)])
}
}

View File

@ -2,10 +2,12 @@
mod hide;
mod image;
mod line;
mod shape;
mod transform;
pub use self::image::*;
pub use hide::*;
pub use line::*;
pub use shape::*;
pub use transform::*;

View File

@ -53,6 +53,7 @@ pub fn new() -> Scope {
// Graphics.
std.def_node::<graphics::ImageNode>("image");
std.def_node::<graphics::LineNode>("line");
std.def_node::<graphics::RectNode>("rect");
std.def_node::<graphics::SquareNode>("square");
std.def_node::<graphics::EllipseNode>("ellipse");
@ -170,3 +171,14 @@ castable! {
Expected: "content",
Value::Content(content) => content.pack(),
}
castable! {
Spec<Linear>,
Expected: "two-dimensional length array",
Value::Array(array) => {
let e = "point array must contain exactly two entries";
let a = array.get(0).map_err(|_| e)?.clone().cast::<Linear>()?;
let b = array.get(1).map_err(|_| e)?.clone().cast::<Linear>()?;
Spec::new(a, b)
},
}

BIN
tests/ref/graphics/line.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -0,0 +1,47 @@
// Test lines
---
// Default line.
#line()
---
// Test the to argument.
{
line(to: (10pt, 0pt))
line(origin: (0pt, 10pt), to: (0pt, 0pt))
line(to: (15pt, 15pt))
}
#v(.5cm)
---
#set page(fill: rgb("0B1026"))
#set line(stroke: white)
#let star(width, ..args) = box(width: width, height: width)[
#set text(spacing: 0%)
#set line(..args)
#line(length: +30%, origin: (09.0%, 02%))
#line(length: +30%, origin: (38.7%, 02%), angle: -72deg)
#line(length: +30%, origin: (57.5%, 02%), angle: 252deg)
#line(length: +30%, origin: (57.3%, 02%))
#line(length: -30%, origin: (88.0%, 02%), angle: -36deg)
#line(length: +30%, origin: (73.3%, 48%), angle: 252deg)
#line(length: -30%, origin: (73.5%, 48%), angle: 36deg)
#line(length: +30%, origin: (25.4%, 48%), angle: -36deg)
#line(length: +30%, origin: (25.6%, 48%), angle: -72deg)
#line(length: +32%, origin: (8.50%, 02%), angle: 34deg)
]
#grid(columns: (1fr, ) * 3, ..((star(20pt, thickness: .5pt), ) * 9))
---
// Test errors.
// Error: 11-18 point array must contain exactly two entries
#line(to: (50pt,))
---
// Error: 15-27 expected relative length, found angle
#line(origin: (3deg, 10pt), length: 5cm)