Beispiel #1
0
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
}
Beispiel #2
0
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
}