package main import ( "errors" "flag" "image" "image/color" "log" "github.com/llgcode/draw2d/draw2dkit" "github.com/llgcode/draw2d/draw2dimg" ) func main() { err := run() if err != nil { log.Fatal(err) } } type projection interface { tile() (width float64, height float64) draw(gc *draw2dimg.GraphicContext, x, y, w, h, scale float64, p palette) } type cabinet struct { } func (cabinet) tile() (float64, float64) { return 150, 140 } func (cabinet) draw(gc *draw2dimg.GraphicContext, x, y, w, h, scale float64, p palette) { dw := func(d float64) float64 { return (d / w) * w * scale } dh := func(d float64) float64 { return (d / h) * h * scale } gc.MoveTo(x, y+dh(40)) gc.LineTo(x, y+h) gc.LineTo(x+dw(100), y+h) gc.LineTo(x+w, y+dh(100)) gc.LineTo(x+w, y) gc.LineTo(x+dw(100), y+dh(40)) gc.LineTo(x+dw(100), y+h) gc.MoveTo(x+dw(100), y+dh(40)) gc.LineTo(x, y+dh(40)) gc.LineTo(x+dw(50), y) gc.LineTo(x+w, y) gc.LineTo(x+dw(100), y+dh(40)) gc.SetStrokeColor(p.tile) gc.Stroke() } type isometric struct { } func (isometric) tile() (float64, float64) { return 140, 200 } type palette struct { margin color.Color tile color.Color } func (isometric) draw(gc *draw2dimg.GraphicContext, x, y, w, h, scale float64, p palette) { gc.MoveTo(x, y+.25*h) gc.LineTo(x, y+.75*h) gc.LineTo(x+.5*w, y+h) gc.LineTo(x+w, y+.75*h) gc.LineTo(x+w, y+.25*h) gc.LineTo(x+.5*w, y+.5*h) gc.LineTo(x, y+.25*h) gc.LineTo(x+.5*w, y) gc.LineTo(x+w, y+.25*h) gc.MoveTo(x+.5*w, y+.5*h) gc.LineTo(x+.5*w, y+h) gc.SetStrokeColor(p.tile) gc.Stroke() } func run() error { var dpi int var proj string flag.IntVar(&dpi, "dpi", 300, "dpi") flag.StringVar(&proj, "projection", "", "projection: either isometric (default) or cabinet") flag.Parse() path := flag.Arg(0) if path == "" { return errors.New("no output path specified") } var p projection switch proj { case "cabinet": p = cabinet{} default: p = isometric{} } bounds := image.Rect(0, 0, dpi*827/100, dpi*1169/100) scale := float64(dpi) / 100 margin := 5. * scale tileWidth, tileHeight := p.tile() tileWidth, tileHeight = tileWidth*scale, tileHeight*scale tileOffsetWidth, tileOffsetHeight := tileWidth+4.*margin, tileHeight+4.*margin im := image.NewRGBA(bounds) gc := draw2dimg.NewGraphicContext(im) gc.SetLineWidth(1) palette := palette{margin: color.Gray{Y: 63}, tile: color.Gray{Y: 127}} for y := 0.; y < float64(bounds.Max.Y)-tileOffsetHeight; y += tileOffsetHeight { for x := 0.; x < float64(bounds.Max.X)-tileOffsetWidth; x += tileOffsetWidth { draw2dkit.Rectangle(gc, x+margin-1, y+margin-1, x+tileOffsetWidth-margin, y+tileOffsetHeight-margin) gc.SetStrokeColor(palette.margin) gc.Stroke() tileX, tileY := x+2*margin-.5, y+2*margin-.5 p.draw(gc, tileX, tileY, tileWidth, tileHeight, scale, palette) } } return draw2dimg.SaveToPngFile(path, im) }