mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
LineNode
This commit is contained in:
parent
288a926fea
commit
4d617bcd67
@ -40,6 +40,16 @@ impl Angle {
|
|||||||
(self.0).0
|
(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.
|
/// Create an angle from a value in a unit.
|
||||||
pub fn with_unit(val: f64, unit: AngularUnit) -> Self {
|
pub fn with_unit(val: f64, unit: AngularUnit) -> Self {
|
||||||
Self(Scalar(val * unit.raw_scale()))
|
Self(Scalar(val * unit.raw_scale()))
|
||||||
|
@ -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 {
|
impl Get<SpecAxis> for Point {
|
||||||
type Component = Length;
|
type Component = Length;
|
||||||
|
|
||||||
|
61
src/library/graphics/line.rs
Normal file
61
src/library/graphics/line.rs
Normal 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)])
|
||||||
|
}
|
||||||
|
}
|
@ -2,10 +2,12 @@
|
|||||||
|
|
||||||
mod hide;
|
mod hide;
|
||||||
mod image;
|
mod image;
|
||||||
|
mod line;
|
||||||
mod shape;
|
mod shape;
|
||||||
mod transform;
|
mod transform;
|
||||||
|
|
||||||
pub use self::image::*;
|
pub use self::image::*;
|
||||||
pub use hide::*;
|
pub use hide::*;
|
||||||
|
pub use line::*;
|
||||||
pub use shape::*;
|
pub use shape::*;
|
||||||
pub use transform::*;
|
pub use transform::*;
|
||||||
|
@ -53,6 +53,7 @@ pub fn new() -> Scope {
|
|||||||
|
|
||||||
// Graphics.
|
// Graphics.
|
||||||
std.def_node::<graphics::ImageNode>("image");
|
std.def_node::<graphics::ImageNode>("image");
|
||||||
|
std.def_node::<graphics::LineNode>("line");
|
||||||
std.def_node::<graphics::RectNode>("rect");
|
std.def_node::<graphics::RectNode>("rect");
|
||||||
std.def_node::<graphics::SquareNode>("square");
|
std.def_node::<graphics::SquareNode>("square");
|
||||||
std.def_node::<graphics::EllipseNode>("ellipse");
|
std.def_node::<graphics::EllipseNode>("ellipse");
|
||||||
@ -170,3 +171,14 @@ castable! {
|
|||||||
Expected: "content",
|
Expected: "content",
|
||||||
Value::Content(content) => content.pack(),
|
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
BIN
tests/ref/graphics/line.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.4 KiB |
47
tests/typ/graphics/line.typ
Normal file
47
tests/typ/graphics/line.typ
Normal 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)
|
Loading…
x
Reference in New Issue
Block a user