diff --git a/stl/geometry/text.go b/stl/geometry/text.go index 65e83d0..acd360c 100644 --- a/stl/geometry/text.go +++ b/stl/geometry/text.go @@ -135,7 +135,8 @@ func renderText(config textRenderConfig) ([]types.Triangle, error) { for y := 0; y < config.contextHeight; y++ { for x := 0; x < config.contextWidth; x++ { - if isPixelActive(dc, x, y) { + intensity := calculatePixelIntensity(dc, x, y) + if intensity > 0 { xPos := config.startX + float64(x)*config.voxelScale/8 zPos := config.startZ - float64(y)*config.voxelScale/8 @@ -144,7 +145,7 @@ func renderText(config textRenderConfig) ([]types.Triangle, error) { config.startY, zPos, config.voxelScale/2, - config.depth, + config.depth*intensity, config.voxelScale/2, ) if err != nil { @@ -216,7 +217,8 @@ func renderImage(config imageRenderConfig) ([]types.Triangle, error) { for y := height - 1; y >= 0; y-- { for x := 0; x < width; x++ { r, _, _, a := img.At(x, y).RGBA() - if a > 32768 && r > 32768 { + intensity := float64(r) / 65535.0 + if a > 32768 && intensity > 0 { xPos := config.startX + float64(x)*config.voxelScale*scale zPos := config.startZ + float64(height-1-y)*config.voxelScale*scale @@ -225,7 +227,7 @@ func renderImage(config imageRenderConfig) ([]types.Triangle, error) { config.startY, zPos, config.voxelScale*scale, - config.depth, + config.depth*intensity, config.voxelScale*scale, ) @@ -241,8 +243,17 @@ func renderImage(config imageRenderConfig) ([]types.Triangle, error) { return triangles, nil } -// isPixelActive checks if a pixel is active (white) in the given context. -func isPixelActive(dc *gg.Context, x, y int) bool { - r, _, _, _ := dc.Image().At(x, y).RGBA() - return r > 32768 +// calculatePixelIntensity returns the intensity of a pixel at the given coordinates +// as a float64 value between 0.0 (black) and 1.0 (white). +func calculatePixelIntensity(dc *gg.Context, x, y int) float64 { + // Get RGB values from pixel + r, g, b, _ := dc.Image().At(x, y).RGBA() + + // Convert to grayscale + gray := 0.299*float64(r) + 0.587*float64(g) + 0.114*float64(b) + + // Normalize to 0-1 range (RGBA values are in 0-65535 range) + intensity := gray / 65535.0 + + return intensity } diff --git a/stl/geometry/text_test.go b/stl/geometry/text_test.go index c1500a7..598cd97 100644 --- a/stl/geometry/text_test.go +++ b/stl/geometry/text_test.go @@ -110,25 +110,77 @@ func TestRenderImage(t *testing.T) { }) } -// TestIsPixelActive verifies pixel activity detection -func TestIsPixelActive(t *testing.T) { - t.Run("verify white pixel detection", func(t *testing.T) { +// TestCalculatePixelIntensity verifies pixel intensity calculation +func TestCalculatePixelIntensity(t *testing.T) { + t.Run("verify white pixel intensity", func(t *testing.T) { dc := gg.NewContext(1, 1) dc.SetRGB(1, 1, 1) // White dc.Clear() - if !isPixelActive(dc, 0, 0) { - t.Error("Expected white pixel to be active") + if calculatePixelIntensity(dc, 0, 0) <= 0 { + t.Error("Expected white pixel to have positive intensity") } }) - t.Run("verify black pixel detection", func(t *testing.T) { + t.Run("verify black pixel intensity", func(t *testing.T) { dc := gg.NewContext(1, 1) dc.SetRGB(0, 0, 0) // Black dc.Clear() - if isPixelActive(dc, 0, 0) { - t.Error("Expected black pixel to be inactive") + if calculatePixelIntensity(dc, 0, 0) > 0 { + t.Error("Expected black pixel to have zero intensity") + } + }) + + t.Run("verify grayscale pixel intensity", func(t *testing.T) { + dc := gg.NewContext(1, 1) + dc.SetRGB(0.5, 0.5, 0.5) // Gray + dc.Clear() + + intensity := calculatePixelIntensity(dc, 0, 0) + if intensity <= 0 || intensity >= 1 { + t.Errorf("Expected grayscale pixel to have intensity between 0 and 1, got %f", intensity) + } + }) + + t.Run("verify gradient circle intensity", func(t *testing.T) { + // Create a 100x100 image with a radial gradient circle + size := 100 + dc := gg.NewContext(size, size) + dc.SetRGB(0, 0, 0) + dc.Clear() + + // Draw a single circle with gradient + centerX, centerY := float64(size/2), float64(size/2) + radius := float64(size / 2) + + // Create radial gradient + gradient := gg.NewRadialGradient(centerX, centerY, 0, centerX, centerY, radius) + gradient.AddColorStop(0, color.White) + gradient.AddColorStop(1, color.Black) + + dc.SetFillStyle(gradient) + dc.DrawCircle(centerX, centerY, radius) + dc.Fill() + + // Test points at different distances from center + testPoints := []struct { + x, y int + minRange float64 + maxRange float64 + }{ + {size / 2, size / 2, 0.9, 1.0}, // Center (highest intensity) + {size / 4, size / 4, 0.3, 0.7}, // Quarter way (medium intensity) + {size - 1, size - 1, 0.0, 0.1}, // Corner (lowest intensity) + } + + for _, pt := range testPoints { + intensity := calculatePixelIntensity(dc, pt.x, pt.y) + t.Logf("Pixel at (%d,%d) has intensity %f", pt.x, pt.y, intensity) + if intensity < pt.minRange || intensity > pt.maxRange { + t.Errorf("Pixel at (%d,%d) has intensity %f, expected between %f and %f", + pt.x, pt.y, intensity, pt.minRange, pt.maxRange) + } } }) }