-
-
Save gugray/7fad069724bdc957ac1b40ce03a47a03 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"bufio" | |
"fmt" | |
"math" | |
"os" | |
"strconv" | |
"strings" | |
"time" | |
) | |
const pixelFileName = "pixels.txt" | |
const lineFileName = "lines.txt" | |
const w = 1480 | |
const h = 1050 | |
const rf = 2 | |
const segLen = 2 | |
var img image | |
var lines []inputLine | |
var visibleLines []outputLine | |
type pixel struct { | |
r, g, b byte | |
} | |
type point struct { | |
x, y float64 | |
} | |
type pixelRow []pixel | |
type image struct { | |
rows []pixelRow | |
} | |
type inputLine struct { | |
pt1, pt2 point | |
clr1, clr2 pixel | |
} | |
type outputLine struct { | |
pt1, pt2 point | |
} | |
func main() { | |
readLines() | |
readImage() | |
tStart := time.Now() | |
var res []outputLine | |
for i, _ := range lines { | |
ln := lines[i] | |
res = getVisibleLines(res, ln) | |
visibleLines = append(visibleLines, res...) | |
} | |
elapsed := time.Since(tStart) | |
fmt.Printf("Elapsed: %v\n", elapsed) | |
fmt.Printf("Kept %v lines\n", len(visibleLines)) | |
} | |
func getVisibleLines(visibleLines []outputLine, ln inputLine) []outputLine { | |
visibleLines = visibleLines[:0] | |
delta := point{ln.pt2.x - ln.pt1.x, ln.pt2.y - ln.pt1.y} | |
lineLength := math.Sqrt(delta.x*delta.x + delta.y*delta.y) | |
nSegs := int(math.Max(2, math.Round(lineLength/segLen))) | |
orto := point{-delta.y / lineLength, delta.x / lineLength} | |
gotFirstVisible := false | |
var firstVisible, pt, prevPt point | |
for i := 0; i <= nSegs; i++ { | |
pt.x = ln.pt1.x + float64(i)/float64(nSegs)*delta.x | |
pt.y = ln.pt1.y + float64(i)/float64(nSegs)*delta.y | |
clrHere := getPixel(pt) | |
isVisible := clrEq(clrHere, ln.clr1) | |
if !isVisible { | |
isVisible = clrEq(clrHere, ln.clr2) | |
} | |
if !isVisible { | |
clrHere = getPixel(point{pt.x + orto.x, pt.y + orto.y}) | |
isVisible = clrEq(clrHere, ln.clr1) | |
if !isVisible { | |
isVisible = clrEq(clrHere, ln.clr2) | |
} | |
} | |
if !isVisible { | |
clrHere = getPixel(point{pt.x - orto.x, pt.y - orto.y}) | |
isVisible = clrEq(clrHere, ln.clr1) | |
if !isVisible { | |
isVisible = clrEq(clrHere, ln.clr2) | |
} | |
} | |
if isVisible && !gotFirstVisible { | |
firstVisible = pt | |
gotFirstVisible = true | |
} else if !isVisible && gotFirstVisible { | |
if firstVisible != prevPt { | |
visibleLines = append(visibleLines, outputLine{firstVisible, prevPt}) | |
} | |
gotFirstVisible = false | |
} | |
prevPt = pt | |
} | |
if gotFirstVisible && firstVisible != ln.pt2 { | |
visibleLines = append(visibleLines, outputLine{firstVisible, ln.pt2}) | |
} | |
return visibleLines | |
} | |
func getPixel(pt point) pixel { | |
x := int(math.Round(pt.x * rf)) | |
y := h*rf - int(math.Round(pt.y*rf)) | |
if x < 0 || x >= w*rf || y < 0 || y >= h*rf { | |
return pixel{} | |
} | |
return img.rows[y][x] | |
} | |
func clrEq(a, b pixel) bool { | |
return areClose(a.r, b.r) && areClose(a.g, b.g) && areClose(a.b, b.b) | |
} | |
func areClose(a, b byte) bool { | |
if a == b { | |
return true | |
} | |
if a > b && a == b+1 { | |
return true | |
} | |
if b > a && b == a+1 { | |
return true | |
} | |
return false | |
} | |
func readLines() { | |
file, err := os.Open(lineFileName) | |
if err != nil { | |
panic(err) | |
} | |
defer file.Close() | |
scanner := bufio.NewScanner(file) | |
for scanner.Scan() { | |
vals := strings.Fields(scanner.Text()) | |
var ln inputLine | |
var err error | |
if ln.pt1.x, err = strconv.ParseFloat(vals[0], 64); err != nil { | |
panic(err) | |
} | |
if ln.pt1.y, err = strconv.ParseFloat(vals[1], 64); err != nil { | |
panic(err) | |
} | |
if ln.pt2.x, err = strconv.ParseFloat(vals[2], 64); err != nil { | |
panic(err) | |
} | |
if ln.pt2.y, err = strconv.ParseFloat(vals[3], 64); err != nil { | |
panic(err) | |
} | |
var r, g, b int | |
if r, err = strconv.Atoi(vals[4]); err != nil { | |
panic(err) | |
} | |
if g, err = strconv.Atoi(vals[5]); err != nil { | |
panic(err) | |
} | |
if b, err = strconv.Atoi(vals[6]); err != nil { | |
panic(err) | |
} | |
ln.clr1 = pixel{byte(r), byte(g), byte(b)} | |
if r, err = strconv.Atoi(vals[7]); err != nil { | |
panic(err) | |
} | |
if g, err = strconv.Atoi(vals[8]); err != nil { | |
panic(err) | |
} | |
if b, err = strconv.Atoi(vals[9]); err != nil { | |
panic(err) | |
} | |
ln.clr2 = pixel{byte(r), byte(g), byte(b)} | |
lines = append(lines, ln) | |
} | |
if err := scanner.Err(); err != nil { | |
panic(err) | |
} | |
fmt.Printf("Parsed %d lines\n", len(lines)) | |
} | |
func readImage() { | |
file, err := os.Open(pixelFileName) | |
if err != nil { | |
panic(err) | |
} | |
defer file.Close() | |
scanner := bufio.NewScanner(file) | |
for scanner.Scan() { | |
ln := scanner.Text() | |
vals := strings.Fields(ln) | |
if len(vals)/4 != w*rf { | |
panic(fmt.Sprintf("Expected %d pixels in row, got %d", w*rf, len(vals)/4)) | |
} | |
var row pixelRow | |
for i := 0; i < len(vals)/4; i++ { | |
var r, g, b int | |
var err error | |
if r, err = strconv.Atoi(vals[i*4]); err != nil { | |
panic(err) | |
} | |
if g, err = strconv.Atoi(vals[i*4+1]); err != nil { | |
panic(err) | |
} | |
if b, err = strconv.Atoi(vals[i*4+2]); err != nil { | |
panic(err) | |
} | |
px := pixel{byte(r), byte(g), byte(b)} | |
row = append(row, px) | |
} | |
img.rows = append(img.rows, row) | |
} | |
if err := scanner.Err(); err != nil { | |
panic(err) | |
} | |
if len(img.rows) != h*rf { | |
panic(fmt.Sprintf("Expected %d rows in image, got %d", h*rf, len(img.rows))) | |
} | |
fmt.Printf("Parsed %d x %d image\n", w, h) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment