Skip to content

Commit

Permalink
line: Add center anchor
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-wolf committed Jul 19, 2024
1 parent e931c83 commit cfd6565
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/draw/shapes.typ
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#import "/src/anchor.typ" as anchor_
#import "/src/mark.typ" as mark_
#import "/src/mark-shapes.typ" as mark-shapes_
#import "/src/polygon.typ"
#import "/src/aabb.typ"

#import "transformations.typ": *
Expand Down Expand Up @@ -504,6 +505,7 @@
///
/// = Anchors
/// Supports path anchors.
/// The `"center"` anchor is calculated for triangles or closed polygons if all vertices share the same z value.
///
/// - ..pts-style (coordinates, style): Positional two or more coordinates to draw lines between. Accepts style key-value pairs.
/// - close (bool): If true, the line-strip gets closed to form a polygon
Expand Down Expand Up @@ -566,10 +568,17 @@
close: close
)

// Find center for simple polygons, might return none
let center = if close {
polygon.simple-centroid(pts)
}

// Get bounds
let (transform, anchors) = anchor_.setup(
auto,
(),
name => {
if name == "center" { return center }
},
if center != none { ("center",) } else { () },
name: name,
transform: ctx.transform,
path-anchors: true,
Expand Down
33 changes: 33 additions & 0 deletions src/polygon.typ
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,36 @@
none
}
}

// Calculate triangle centroid
#let triangle-centroid(points) = {
let (mx, my, mz) = points.first()
let n = points.len()
for p in points {
let (x, y, z) = p
mx += x / n
my += y / n
mz += z / n
}
return (mx, my, mz)
}

// Calculate the centroid of a line, triangle or simple polygon
// Formulas:
// https://en.wikipedia.org/wiki/Centroid
#let simple-centroid(points) = {
return if points.len() == 2 {
vector.lerp(..points, .5)
} else if points.len() == 3 {
calc-triangle-centroid(points)
} else if points.len() > 3 {
// Skip polygons with multiple z values
let z = points.first().at(2, default: 0)
if points.any(p => p.at(2) != z) {
return none
}

let a = signed-area(points)
return (cx/(6*a), cy/(6*a), z)
}
}

0 comments on commit cfd6565

Please sign in to comment.