func pruneEdgeDuplicates(edges []math.Vec2) []math.Vec2 { pruned := make([]math.Vec2, 0, len(edges)) last := math.Vec2{} for i, v := range edges { if i == 0 || last.Sub(v).Len() > 0.0001 { pruned = append(pruned, v) } last = v } return pruned }
func segment(penWidth, r float32, a, b, c math.Vec2, aIsLast bool, vsEdgePos []float32, fillEdge []math.Vec2) ([]float32, []math.Vec2) { ba, ca := a.Sub(b), a.Sub(c) baLen, caLen := ba.Len(), ca.Len() baDir, caDir := ba.DivS(baLen), ca.DivS(caLen) dp := baDir.Dot(caDir) if dp < -0.99999 { // Straight lines cause DBZs, special case inner := a.Sub(caDir.Tangent().MulS(penWidth)) vsEdgePos = appendVec2(vsEdgePos, a, inner) if fillEdge != nil /*&& i != 0*/ { fillEdge = append(fillEdge, inner) } return vsEdgePos, fillEdge } α := math.Acosf(dp) / 2 // ╔═══════════════════════════╦════════════════╗ // ║ ║ ║ // ║ A ║ ║ // ║ ╱:╲ ║ ║ // ║ ╱α:α╲ ║ A ║ // ║ ╱ : ╲ ║ |╲ ║ // ║ ╱ . d . ╲ ║ |α╲ ║ // ║ . : . ║ | ╲ ║ // ║ .P : Q. ║ | ╲ ║ // ║ ╱ X ╲ ║ | ╲ ║ // ║ ╱ . ┊ . ╲ ║ | ╲ ║ // ║ ╱ . r . ╲ ║ | ╲ ║ // ║ ╱ . ┊ . ╲ ║ |┐ β╲ ║ // ║ B ┊ C ║ P————————X ║ // ║ ║ ║ // ║ ^ ║ ║ // ║ ┊v ║ ║ // ║ ┊ u ║ ║ // ║ ┊—————> ║ ║ // ║ ║ ║ // ╚═══════════════════════════╩════════════════╝ v := baDir.Add(caDir).Normalize() u := v.Tangent() // // cos(2 • α) = dp // // cos⁻¹(dp) // α = ─────────── // 2 // // r // sin(α) = ─── // d // // r // d = ────── // sin(α) // d := r / math.Sinf(α) // X cannot be futher than half way along ab or ac dMax := math.Minf(baLen, caLen) / (2 * math.Cosf(α)) if d > dMax { // Adjust d and r to compensate d = dMax r = d * math.Sinf(α) } x := a.Sub(v.MulS(d)) convex := baDir.Tangent().Dot(caDir) <= 0 w := penWidth β := math.Pi/2 - α // Special case for convex vertices where the pen width is greater than // the rounding. Without dealing with this, we'd end up with the inner // vertices overlapping. Instead use a point calculated much the same as // x, but using the pen width. useFixedInnerPoint := convex && w > r fixedInnerPoint := a.Sub(v.MulS(math.Minf(w/math.Sinf(α), dMax))) // Concave vertices behave much the same as convex, but we have to flip // β as the sweep is reversed and w as we're extruding. if !convex { w, β = -w, -β } steps := 1 + int(d*α) if aIsLast { // No curvy edge required for the last vertex. // This is already done by the first vertex. steps = 1 } for j := 0; j < steps; j++ { γ := float32(0) if steps > 1 { γ = math.Lerpf(-β, β, float32(j)/float32(steps-1)) } dir := v.MulS(math.Cosf(γ)).Add(u.MulS(math.Sinf(γ))) va := x.Add(dir.MulS(r)) vb := va.Sub(dir.MulS(w)) if useFixedInnerPoint { vb = fixedInnerPoint } vsEdgePos = appendVec2(vsEdgePos, va, vb) if fillEdge != nil { fillEdge = append(fillEdge, vb) } } return vsEdgePos, fillEdge }