vector: add some more tests.
These tests are copied from the github.com/google/font-go prototype.
Change-Id: I4523193bd3453974633cbef0576c1203eb013a7d
Reviewed-on: https://go-review.googlesource.com/29697
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/vector/vector.go b/vector/vector.go
index b7a4594..e11c721 100644
--- a/vector/vector.go
+++ b/vector/vector.go
@@ -59,6 +59,9 @@
}
// Raster is a 2-D vector graphics rasterizer.
+//
+// The zero value is usable, in that it is a Rasterizer whose rendered mask
+// image has zero width and zero height. Call Reset to change its bounds.
type Rasterizer struct {
// bufXxx are buffers of float32 or uint32 values, holding either the
// individual or cumulative area values.
diff --git a/vector/vector_test.go b/vector/vector_test.go
index a7c3551..fb8e7fd 100644
--- a/vector/vector_test.go
+++ b/vector/vector_test.go
@@ -14,6 +14,7 @@
"image/png"
"math"
"os"
+ "path/filepath"
"testing"
"golang.org/x/image/math/f32"
@@ -33,6 +34,117 @@
return closeErr
}
+func pointOnCircle(center, radius, index, number int) f32.Vec2 {
+ c := float64(center)
+ r := float64(radius)
+ i := float64(index)
+ n := float64(number)
+ return f32.Vec2{
+ float32(c + r*(math.Cos(2*math.Pi*i/n))),
+ float32(c + r*(math.Sin(2*math.Pi*i/n))),
+ }
+}
+
+func TestRasterizeOutOfBounds(t *testing.T) {
+ // Set this to a non-empty string such as "/tmp" to manually inspect the
+ // rasterization.
+ //
+ // If empty, this test simply checks that calling LineTo with points out of
+ // the rasterizer's bounds doesn't panic.
+ const tmpDir = ""
+
+ const center, radius, n = 16, 20, 16
+ var z Rasterizer
+ for i := 0; i < n; i++ {
+ for j := 1; j < n/2; j++ {
+ z.Reset(2*center, 2*center)
+ z.MoveTo(f32.Vec2{1 * center, 1 * center})
+ z.LineTo(pointOnCircle(center, radius, i+0, n))
+ z.LineTo(pointOnCircle(center, radius, i+j, n))
+ z.ClosePath()
+
+ z.MoveTo(f32.Vec2{0 * center, 0 * center})
+ z.LineTo(f32.Vec2{0 * center, 2 * center})
+ z.LineTo(f32.Vec2{2 * center, 2 * center})
+ z.LineTo(f32.Vec2{2 * center, 0 * center})
+ z.ClosePath()
+
+ dst := image.NewAlpha(z.Bounds())
+ z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
+
+ if tmpDir == "" {
+ continue
+ }
+
+ filename := filepath.Join(tmpDir, fmt.Sprintf("out-%02d-%02d.png", i, j))
+ if err := encodePNG(filename, dst); err != nil {
+ t.Error(err)
+ }
+ t.Logf("wrote %s", filename)
+ }
+ }
+}
+
+func TestRasterizePolygon(t *testing.T) {
+ var z Rasterizer
+ for radius := 4; radius <= 1024; radius *= 2 {
+ for n := 3; n <= 19; n += 4 {
+ z.Reset(2*radius, 2*radius)
+ z.MoveTo(f32.Vec2{
+ float32(2 * radius),
+ float32(1 * radius),
+ })
+ for i := 1; i < n; i++ {
+ z.LineTo(pointOnCircle(radius, radius, i, n))
+ }
+ z.ClosePath()
+
+ dst := image.NewAlpha(z.Bounds())
+ z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
+
+ if err := checkCornersCenter(dst); err != nil {
+ t.Errorf("radius=%d, n=%d: %v", radius, n, err)
+ }
+ }
+ }
+}
+
+func TestRasterizeAlmostAxisAligned(t *testing.T) {
+ z := NewRasterizer(8, 8)
+ z.MoveTo(f32.Vec2{2, 2})
+ z.LineTo(f32.Vec2{6, math.Nextafter32(2, 0)})
+ z.LineTo(f32.Vec2{6, 6})
+ z.LineTo(f32.Vec2{math.Nextafter32(2, 0), 6})
+ z.ClosePath()
+
+ dst := image.NewAlpha(z.Bounds())
+ z.Draw(dst, dst.Bounds(), image.Opaque, image.Point{})
+
+ if err := checkCornersCenter(dst); err != nil {
+ t.Error(err)
+ }
+}
+
+// checkCornersCenter checks that the corners of the image are all 0x00 and the
+// center is 0xff.
+func checkCornersCenter(m *image.Alpha) error {
+ size := m.Bounds().Size()
+ corners := [4]uint8{
+ m.Pix[(0*size.Y+0)*m.Stride+(0*size.X+0)],
+ m.Pix[(0*size.Y+0)*m.Stride+(1*size.X-1)],
+ m.Pix[(1*size.Y-1)*m.Stride+(0*size.X+0)],
+ m.Pix[(1*size.Y-1)*m.Stride+(1*size.X-1)],
+ }
+ if corners != [4]uint8{} {
+ return fmt.Errorf("corners were not all zero: %v", corners)
+ }
+ center := m.Pix[(size.Y/2)*m.Stride+(size.X/2)]
+ if center != 0xff {
+ return fmt.Errorf("center: got %#02x, want 0xff", center)
+ }
+ return nil
+}
+
var basicMask = []byte{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,