BrickMosaic

package module
v0.0.0-...-964feaf Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2014 License: MIT Imports: 8 Imported by: 1

README

BrickMosaic

A program for converting images into LEGO mosaics.

Installation

Get the svg library:

go get github.com/ajstarks/svgo

Get the mosaic library:

go get github.com/I82Much/BrickMosaic

Build the library:

go build github.com/I82Much/BrickMosaic

Run the binary:

go run main.go --path=/path/to/image.jpg --output_path=/path/to/destination.svg

Once the program is complete, you can view the svg in a web browser to see the instructions.

Examples:

Darth Vader

Here is the Darth Vader mosaic I created earlier this summer using a prior version of this program:

Darth Vader finished Darth Vader in progress

Iron Man

Here are three versions of Iron Man (original image):

Studs Up: Iron Man Studs Top

Studs Right: Iron Man Studs Right

Studs Out: Iron Man Studs Out

Documentation

Overview

package grid represents a 2d array of coordinates and their state as we build the mosaic. Its coordinates are divorced from the physical coordinate system. For instance, we treat all mosaics as the same grid coordinate system, regardless of whether we are building them top down, or from the top down, or from left to right. This grid abstracts away the physical dimensions of the bricks and allows us to concentrate on the core algorithm. This is handled via the Piece interface defined in piece.go.

In each orientation, a column of the grid has width equal to the smallest width piece, and a row is as high as the smallest height piece. For instance, if we are looking top down at a mosaic, each row and column is of equal size. If we are building a studs up mosaic, the row is equal in height to a single plate, and the column would be equal to the width of a single 1x1. If we are building a studs right mosaic, the row is equal to the width of a single 1x1 and the column would be equal to the height of a plate.

The grid is indexed such that [0][0] is the upper left corner and [numRows-1][numColumns-1] is the lower right corner.

Inventory is a convenience helper for determining how many pieces of which color are used in the model. This makes it easier to actually procure the pieces necessary to build the physical version of the model.

Package palette represents the colors of LEGO bricks. It defines sets of colors that will be used as the palette for creating the final mosaic (any color not in the palette will be ignored).

Package render is concerned with rendering Plans.

This file is responsible for rendering svg instructions of how to build a given plan.

Index

Constants

This section is empty.

Variables

View Source
var (
	// OneByEight represents a 1 x 8 brick. See http://lego.wikia.com/wiki/Part_3008.
	OneByEight = brick{
				// contains filtered or unexported fields
	}

	// OneBySix represents a 1 x 6 brick. See http://lego.wikia.com/wiki/Part_3009.
	OneBySix = brick{
				// contains filtered or unexported fields
	}

	// OneByFour represents a 1 x 4 brick. See http://lego.wikia.com/wiki/Part_3010.
	OneByFour = brick{
				// contains filtered or unexported fields
	}

	// OneByThree represents a 1 x 3 brick. See http://lego.wikia.com/wiki/Part_3622.
	OneByThree = brick{
				// contains filtered or unexported fields
	}
	// OneByTwo represents a 1 x 2 brick. See http://lego.wikia.com/wiki/Part_3004.
	OneByTwo = brick{
				// contains filtered or unexported fields
	}
	// OneByOne represents a 1 x 1 brick. See http://lego.wikia.com/wiki/Part_3005.
	OneByOne = brick{
				// contains filtered or unexported fields
	}

	// TwoByEight represents a 2 x 8 brick. See http://lego.wikia.com/wiki/Part_3007.
	TwoByEight = brick{
				// contains filtered or unexported fields
	}

	// TwoBySix represents a 2 x 6 brick. See http://lego.wikia.com/wiki/Part_2456.
	TwoBySix = brick{
				// contains filtered or unexported fields
	}

	// TwoByFour represents a 2 x 4 brick. See http://lego.wikia.com/wiki/Part_3001.
	TwoByFour = brick{
				// contains filtered or unexported fields
	}
	// TwoByThree represents a 2 x 3 brick. See http://lego.wikia.com/wiki/Part_3002.
	TwoByThree = brick{
				// contains filtered or unexported fields
	}
	// TwoByTwo represents a 2 x 2 brick. See http://lego.wikia.com/wiki/Part_3003.
	TwoByTwo = brick{
				// contains filtered or unexported fields
	}

	// OneByPlate represents a 1 x 1 plate. See http://lego.wikia.com/wiki/Part_3024.
	OneByOnePlate = brick{
					// contains filtered or unexported fields
	}
	// OneByTwoPlate represents a 1 x 2 plate. See http://lego.wikia.com/wiki/Part_3023.
	OneByTwoPlate = brick{
					// contains filtered or unexported fields
	}
	// OneByThreePlate represents a 1 x 3 plate. See http://lego.wikia.com/wiki/Part_3623.
	OneByThreePlate = brick{
					// contains filtered or unexported fields
	}
	// OneByFourPlate represents a 1 x 4 plate. See http://lego.wikia.com/wiki/Part_3710.
	OneByFourPlate = brick{
					// contains filtered or unexported fields
	}
	// OneBySixPlate represents a 1 x 6 plate. See http://lego.wikia.com/wiki/Part_3666.
	OneBySixPlate = brick{
					// contains filtered or unexported fields
	}
	// OneByEightPlate represents a 1 x 8 plate. See http://brickowl.com/catalog/lego-plate-1-x-8-3460.
	OneByEightPlate = brick{
					// contains filtered or unexported fields
	}
	// OneByTenPlate represents a 1 x 10 plate. See http://brickowl.com/catalog/lego-plate-1-x-10-4477.
	OneByTenPlate = brick{
					// contains filtered or unexported fields
	}

	// Bricks represents a slice of all of the bricks (full height, not plates). They are listed in descending
	// order of area.
	Bricks = []Brick{
		TwoByEight,
		TwoBySix,
		TwoByFour,
		TwoByThree,
		TwoByTwo,

		OneByEight,
		OneBySix,
		OneByFour,
		OneByThree,
		OneByTwo,
		OneByOne,
	}

	// Plates represents a slice of all of the standard plates (thinner than bricks). They are listed in
	// descending order of area.
	Plates = []Brick{
		OneByTenPlate,
		OneByEightPlate,
		OneBySixPlate,
		OneByFourPlate,
		OneByThreePlate,
		OneByTwoPlate,
		OneByOnePlate,
	}

	// Pieces represents a slice of all of the standard Bricks; the concatenation of Bricks and Plates.
	Pieces = allBricks()
)
View Source
var (
	Red = color.RGBA{uint8(200), 0, 0, 0}

	// All color RGB values from
	// http://www.peeron.com/cgi-bin/invcgis/colorguide.cgi
	// cat ~/Dropbox/BrickColors.txt  | awk '{print $2 " = BrickColor{name: \"" $2 "\", c:color.ARGB{R:uint8(" $7 "), G:uint8(" $8 "), B:uint8(" $9 "), A:uint8(0)}}"}' | mate
	White                 = BrickColor{/* contains filtered or unexported fields */}
	Grey                  = BrickColor{/* contains filtered or unexported fields */}
	LightYellow           = BrickColor{/* contains filtered or unexported fields */}
	BrickYellow           = BrickColor{/* contains filtered or unexported fields */}
	LightGreen            = BrickColor{/* contains filtered or unexported fields */}
	LightReddishViolet    = BrickColor{/* contains filtered or unexported fields */}
	LightOrangeBrown      = BrickColor{/* contains filtered or unexported fields */}
	Nougat                = BrickColor{/* contains filtered or unexported fields */}
	BrightRed             = BrickColor{/* contains filtered or unexported fields */}
	MedReddishViolet      = BrickColor{/* contains filtered or unexported fields */}
	BrightBlue            = BrickColor{/* contains filtered or unexported fields */}
	BrightYellow          = BrickColor{/* contains filtered or unexported fields */}
	EarthOrange           = BrickColor{/* contains filtered or unexported fields */}
	Black                 = BrickColor{/* contains filtered or unexported fields */}
	DarkGrey              = BrickColor{/* contains filtered or unexported fields */}
	DarkGreen             = BrickColor{/* contains filtered or unexported fields */}
	MediumGreen           = BrickColor{/* contains filtered or unexported fields */}
	LightYellowishOrange  = BrickColor{/* contains filtered or unexported fields */}
	BrightGreen           = BrickColor{/* contains filtered or unexported fields */}
	DarkOrange            = BrickColor{/* contains filtered or unexported fields */}
	LightBluishViolet     = BrickColor{/* contains filtered or unexported fields */}
	LightBlue             = BrickColor{/* contains filtered or unexported fields */}
	LightRed              = BrickColor{/* contains filtered or unexported fields */}
	MediumRed             = BrickColor{/* contains filtered or unexported fields */}
	MediumBlue            = BrickColor{/* contains filtered or unexported fields */}
	LightGrey             = BrickColor{/* contains filtered or unexported fields */}
	BrightViolet          = BrickColor{/* contains filtered or unexported fields */}
	BrightYellowishOrange = BrickColor{/* contains filtered or unexported fields */}
	BrightOrange          = BrickColor{/* contains filtered or unexported fields */}
	BrightBluishGreen     = BrickColor{/* contains filtered or unexported fields */}
	EarthYellow           = BrickColor{/* contains filtered or unexported fields */}
	BrightBluishViolet    = BrickColor{/* contains filtered or unexported fields */}
	MediumBluishViolet    = BrickColor{/* contains filtered or unexported fields */}
	MedYellowishGreen     = BrickColor{/* contains filtered or unexported fields */}
	MedBluishGreen        = BrickColor{/* contains filtered or unexported fields */}
	LightBluishGreen      = BrickColor{/* contains filtered or unexported fields */}
	BrYellowishGreen      = BrickColor{/* contains filtered or unexported fields */}
	LigYellowishGreen     = BrickColor{/* contains filtered or unexported fields */}
	MedYellowishOrange    = BrickColor{/* contains filtered or unexported fields */}
	BrReddishOrange       = BrickColor{/* contains filtered or unexported fields */}
	BrightReddishViolet   = BrickColor{/* contains filtered or unexported fields */}
	LightOrange           = BrickColor{/* contains filtered or unexported fields */}
	Gold                  = BrickColor{/* contains filtered or unexported fields */}
	DarkNougat            = BrickColor{/* contains filtered or unexported fields */}
	Silver                = BrickColor{/* contains filtered or unexported fields */}
	SandBlue              = BrickColor{/* contains filtered or unexported fields */}
	SandViolet            = BrickColor{/* contains filtered or unexported fields */}
	MediumOrange          = BrickColor{/* contains filtered or unexported fields */}
	SandYellow            = BrickColor{/* contains filtered or unexported fields */}
	EarthBlue             = BrickColor{/* contains filtered or unexported fields */}
	EarthGreen            = BrickColor{/* contains filtered or unexported fields */}
	SandBlueMetallic      = BrickColor{/* contains filtered or unexported fields */}
	SandVioletMetallic    = BrickColor{/* contains filtered or unexported fields */}
	SandYellowMetallic    = BrickColor{/* contains filtered or unexported fields */}
	DarkGreyMetallic      = BrickColor{/* contains filtered or unexported fields */}
	BlackMetallic         = BrickColor{/* contains filtered or unexported fields */}
	LightGreyMetallic     = BrickColor{/* contains filtered or unexported fields */}
	Sand                  = BrickColor{/* contains filtered or unexported fields */}
	SandRed               = BrickColor{/* contains filtered or unexported fields */}
	DarkRed               = BrickColor{/* contains filtered or unexported fields */}
	Gun                   = BrickColor{/* contains filtered or unexported fields */}
	Curry                 = BrickColor{/* contains filtered or unexported fields */}
	LemonMetalic          = BrickColor{/* contains filtered or unexported fields */}
	FireYellow            = BrickColor{/* contains filtered or unexported fields */}
	FlameYellowishOrange  = BrickColor{/* contains filtered or unexported fields */}
	ReddishBrown          = BrickColor{/* contains filtered or unexported fields */}
	FlameReddishOrange    = BrickColor{/* contains filtered or unexported fields */}
	MediumStoneGrey       = BrickColor{/* contains filtered or unexported fields */}
	RoyalBlue             = BrickColor{/* contains filtered or unexported fields */}
	DarkRoyalBlue         = BrickColor{/* contains filtered or unexported fields */}
	BrightReddishLilac    = BrickColor{/* contains filtered or unexported fields */}
	DarkStoneGrey         = BrickColor{/* contains filtered or unexported fields */}
	LightStoneGrey        = BrickColor{/* contains filtered or unexported fields */}
	DarkCurry             = BrickColor{/* contains filtered or unexported fields */}
	FadedGreen            = BrickColor{/* contains filtered or unexported fields */}
	Turquoise             = BrickColor{/* contains filtered or unexported fields */}
	LightRoyalBlue        = BrickColor{/* contains filtered or unexported fields */}
	MediumRoyalBlue       = BrickColor{/* contains filtered or unexported fields */}
	Rust                  = BrickColor{/* contains filtered or unexported fields */}
	Brown                 = BrickColor{/* contains filtered or unexported fields */}
	ReddishLilac          = BrickColor{/* contains filtered or unexported fields */}
	Lilac                 = BrickColor{/* contains filtered or unexported fields */}
	LightLilac            = BrickColor{/* contains filtered or unexported fields */}
	BrightPurple          = BrickColor{/* contains filtered or unexported fields */}
	LightPurple           = BrickColor{/* contains filtered or unexported fields */}
	LightPink             = BrickColor{/* contains filtered or unexported fields */}
	LightBrickYellow      = BrickColor{/* contains filtered or unexported fields */}
	WarmYellowishOrange   = BrickColor{/* contains filtered or unexported fields */}
	CoolYellow            = BrickColor{/* contains filtered or unexported fields */}
	DoveBlue              = BrickColor{/* contains filtered or unexported fields */}
	MediumLilac           = BrickColor{/* contains filtered or unexported fields */}
	Transparent           = BrickColor{/* contains filtered or unexported fields */}
	TrRed                 = BrickColor{/* contains filtered or unexported fields */}
	TrLgBlue              = BrickColor{/* contains filtered or unexported fields */}
	TrBlue                = BrickColor{/* contains filtered or unexported fields */}
	TrYellow              = BrickColor{/* contains filtered or unexported fields */}
	TrFluReddishOrange    = BrickColor{/* contains filtered or unexported fields */}
	TrGreen               = BrickColor{/* contains filtered or unexported fields */}
	TrFluGreen            = BrickColor{/* contains filtered or unexported fields */}
	PhosphWhite           = BrickColor{/* contains filtered or unexported fields */}
	TrBrown               = BrickColor{/* contains filtered or unexported fields */}
	TrMediReddishViolet   = BrickColor{/* contains filtered or unexported fields */}
	TrBrightBluishViolet  = BrickColor{/* contains filtered or unexported fields */}
	NeonOrange            = BrickColor{/* contains filtered or unexported fields */}
	NeonGreen             = BrickColor{/* contains filtered or unexported fields */}
	TrFluBlue             = BrickColor{/* contains filtered or unexported fields */}
	TrFluYellow           = BrickColor{/* contains filtered or unexported fields */}
	TrFluRed              = BrickColor{/* contains filtered or unexported fields */}
	RedFlipFlop           = BrickColor{/* contains filtered or unexported fields */}
	YellowFlipFlop        = BrickColor{/* contains filtered or unexported fields */}
	SilverFlipFlop        = BrickColor{/* contains filtered or unexported fields */}

	FullPalette = color.Palette([]color.Color{
		White,
		Grey,
		LightYellow,
		BrickYellow,
		LightGreen,
		LightReddishViolet,
		LightOrangeBrown,
		Nougat,
		BrightRed,
		MedReddishViolet,
		BrightBlue,
		BrightYellow,
		EarthOrange,
		Black,
		DarkGrey,
		DarkGreen,
		MediumGreen,
		LightYellowishOrange,
		BrightGreen,
		DarkOrange,
		LightBluishViolet,
		LightBlue,
		LightRed,
		MediumRed,
		MediumBlue,
		LightGrey,
		BrightViolet,
		BrightYellowishOrange,
		BrightOrange,
		BrightBluishGreen,
		EarthYellow,
		BrightBluishViolet,
		MediumBluishViolet,
		MedYellowishGreen,
		MedBluishGreen,
		LightBluishGreen,
		BrYellowishGreen,
		LigYellowishGreen,
		MedYellowishOrange,
		BrReddishOrange,
		BrightReddishViolet,
		LightOrange,
		Gold,
		DarkNougat,
		Silver,
		SandBlue,
		SandViolet,
		MediumOrange,
		SandYellow,
		EarthBlue,
		EarthGreen,
		SandBlueMetallic,
		SandVioletMetallic,
		SandYellowMetallic,
		DarkGreyMetallic,
		BlackMetallic,
		LightGreyMetallic,
		Sand,
		SandRed,
		DarkRed,
		Gun,
		Curry,
		LemonMetalic,
		FireYellow,
		FlameYellowishOrange,
		ReddishBrown,
		FlameReddishOrange,
		MediumStoneGrey,
		RoyalBlue,
		DarkRoyalBlue,
		BrightReddishLilac,
		DarkStoneGrey,
		LightStoneGrey,
		DarkCurry,
		FadedGreen,
		Turquoise,
		LightRoyalBlue,
		MediumRoyalBlue,
		Rust,
		Brown,
		ReddishLilac,
		Lilac,
		LightLilac,
		BrightPurple,
		LightPurple,
		LightPink,
		LightBrickYellow,
		WarmYellowishOrange,
		CoolYellow,
		DoveBlue,
		MediumLilac,
		Transparent,
		TrRed,
		TrLgBlue,
		TrBlue,
		TrYellow,
		TrFluReddishOrange,
		TrGreen,
		TrFluGreen,
		PhosphWhite,
		TrBrown,
		TrMediReddishViolet,
		TrBrightBluishViolet,
		NeonOrange,
		NeonGreen,
		TrFluBlue,
		TrFluYellow,
		TrFluRed,
		RedFlipFlop,
		YellowFlipFlop,
		SilverFlipFlop,
	})
	LimitedPalette = color.Palette([]color.Color{
		White,
		Grey,
		Black,
		BrightRed,
		BrightBlue,
		BrightYellow,
		DarkGrey,
	})
	GrayPlusPalette = color.Palette([]color.Color{
		White,
		Grey,
		Black,
		DarkGrey,
		LightGrey,
		DarkStoneGrey,
		EarthGreen,
		DarkStoneGrey,
		LightStoneGrey,
		BrightRed,
		BrightBlue,
		BrightYellow,
	})
	GrayScalePalette = color.Palette([]color.Color{
		White,
		Black,
		DarkGrey,
		LightGrey,
		DarkStoneGrey,
	})
	Primary = color.Palette([]color.Color{
		BrightYellow,
		BrightRed,
		BrightBlue,
	})
	BlackAndWhite = color.Palette([]color.Color{
		White,
		Black,
	})
)

Functions

func AddError

func AddError(c color.Color, err QuantizationError) color.Color

AddError adds the given amount of error to the given color, transforming it into a new color. For instance, if c is {R:100, G:100, B:100} and error is {r:-50,g:50,b:-50}, then the final result is {R:50, G:150, B:50}

func ApproxSizeInch

func ApproxSizeInch(size LDU) float32

func ApproxSizeMm

func ApproxSizeMm(size LDU) float32

func AverageColor

func AverageColor(si image.Image, bounds image.Rectangle) color.Color

AverageColor determines the 'average' color of the subimage whose coordinates are contained in the given bounds. The average is an arithmetic average in RGB color space. TODO(ndunn): try different color spaces.

func BoundingBox

func BoundingBox(p Piece, origin Location) (minRow, minCol, maxRow, maxCol int)

Upper left origin

func CalculateRowsAndColumns

func CalculateRowsAndColumns(width, height, maxStuds int, orientation ViewOrientation) (rows, cols int)

func DoRender

func DoRender(p Plan, canvas *svg.SVG)

DoRender writes the plan information to the svg canvas.

func GetDimensionsForBlock

func GetDimensionsForBlock(o ViewOrientation) (width, height int)

Types

type AnchorPoint

type AnchorPoint int
const (
	UpperLeft AnchorPoint = iota
	UpperRight
	LowerRight
	LowerLeft
)

func (AnchorPoint) String

func (a AnchorPoint) String() string

type Brick

type Brick interface {
	Name() string
	Id() string
	Width() int
	Length() int
	Height() int
	// TODO(ndunn): This somehow has to take into account color
	// Cost in cents.
	ApproximateCost() int
}

Brick represents a prototypical piece, not bound to any specific orientation or color.

type BrickColor

type BrickColor struct {
	// contains filtered or unexported fields
}

BrickColor represents the color of a LEGO brick. It implements the color.Color interface via delegation.

func ColorForName

func ColorForName(n string) *BrickColor

ColorForName returns the BrickColor whose name matches n, or nil.

func (BrickColor) RGBA

func (c BrickColor) RGBA() (r, g, b, a uint32)

type BrickImage

type BrickImage struct {

	// Frames are snapshots of the process of creating the final image, for debuggin
	// purposes
	Frames []*image.Paletted
	// contains filtered or unexported fields
}

BrickImage is an implementation of Ideal interface.

func NewBrickImage

func NewBrickImage(img image.Image, rows, cols int, palette color.Palette, o ViewOrientation, errorScalingFactor float32) *BrickImage

NewBrickImage returns a BrickImage based on the given inputs.

func (*BrickImage) Bounds

func (si *BrickImage) Bounds() image.Rectangle

FIXME ndunn base it on the orientation

func (*BrickImage) Color

func (si *BrickImage) Color(row, col int) BrickColor

Color returns the best palette.BrickColor for the given row/column in the image based on the palette this image was instantiated with.

func (*BrickImage) ColorModel

func (si *BrickImage) ColorModel() color.Model

func (*BrickImage) IdealColor

func (si *BrickImage) IdealColor(row, col int) color.Color

IdealColor returns the color that ideally we would use for the row / col combination if we had pieces of every color. Later this will be quantized into the nearest neighbor, into a BrickColor.

func (*BrickImage) NumCols

func (si *BrickImage) NumCols() int

NumRows returns the number of columns in the piece.

func (*BrickImage) NumRows

func (si *BrickImage) NumRows() int

NumRows returns the number of rows in the piece.

func (*BrickImage) Orientation

func (si *BrickImage) Orientation() ViewOrientation

Orientation returns the way in which the image is oriented.

func (*BrickImage) Paletted

func (si *BrickImage) Paletted() *image.Paletted

Paletted renders the current state of the image as a Paletted image. Useful for debugging purposes

type By

type By func(p1, p2 *Piece) bool

TODO(ndunn): finish this, sort by price, size (number of grid lcoations it takes up) By is the type of a "less" function that defines the ordering of its Piece pieces

type ColorUsage

type ColorUsage struct {
	// contains filtered or unexported fields
}

type ColorUsages

type ColorUsages []ColorUsage

func (ColorUsages) Len

func (c ColorUsages) Len() int

func (ColorUsages) Less

func (c ColorUsages) Less(i, j int) bool

func (ColorUsages) Swap

func (c ColorUsages) Swap(i, j int)

type Create

type Create func(i Ideal) Plan

Create is the interface by which we convert Ideal mosaics into a plan for building it. As discussed in Plan, different Creators might build Plans that do not perfectly match the Ideal.

type Grid

type Grid struct {
	Rows, Cols int
	State      [][]State
}

Grid is an abstract representation of the mosaic to assemble.

func NewGrid

func NewGrid(numRows, numCols int) Grid

NewGrid returns an empty grid of size numRows by numCols.

func WithState

func WithState(numRows, numCols int, s State) Grid

WithState is a convenience function for creating a grid whose contents are entirely filled with state s.

func (*Grid) Any

func (g *Grid) Any(s State) bool

Any determines whether any entry in the grid has state s.

func (*Grid) Clone

func (g *Grid) Clone() Grid

Clone returns a copy of the grid.

func (*Grid) Fill

func (g *Grid) Fill(s State)

Fill mutates the given grid to be completely filled with state s.

func (*Grid) Find

func (g *Grid) Find(s State) []Location

Find returns all of the locations that have the given state, in row major order.

func (*Grid) Get

func (g *Grid) Get(row, col int) State

Get returns the state at row, col in the given grid. If the given row, col arguments are out of bounsd, the method returns Empty.

func (*Grid) PieceFits

func (g *Grid) PieceFits(extent []Location, loc Location) bool

PieceFits determines if the given piece can fit at the desired location in the grid, where loc is the upper left hand corner of the piece. Note that orientation is already baked into the Extent() of the piece, which is why it is not an argument to this method.

func (*Grid) Set

func (g *Grid) Set(row, col int, state State)

Set sets the state at the given (row, column) pair in the grid. If it's out of bounds, this does nothing.

func (Grid) String

func (g Grid) String() string

String returns a string representation of the grid, suitable for display in a terminal.

type GridSolver

type GridSolver func(g *Grid, pieces []MosaicPiece) (Solution, error)

GridSolver is the interface for fitting pieces into the given grid.

type Ideal

type Ideal interface {
	Orientation() ViewOrientation
	NumRows() int
	NumCols() int
	Color(row, col int) BrickColor
}

Ideal is the idealized grid of how the mosaic should look. Basically a 2d grid of color.

func DitherPosterize

func DitherPosterize(img image.Image, p color.Palette, rows int, cols int, o ViewOrientation) Ideal

DitherPosterize converts the given image into an Ideal form using a standard amount of dithering (error propagation).

func EucPosterize

func EucPosterize(img image.Image, p color.Palette, rows int, cols int, o ViewOrientation) Ideal

EucPosterize returns an Ideal representation of the image with no dithering.

type IdealImage

type IdealImage interface {
	image.Image
	Ideal
}

IdealImage is an object that implements both the Image interface and the Ideal interface

type Inventory

type Inventory struct {
	// contains filtered or unexported fields
}

func MakeInventory

func MakeInventory() Inventory

func (*Inventory) Add

func (inventory *Inventory) Add(c BrickColor, p Brick)

func (*Inventory) ApproximateCost

func (inventory *Inventory) ApproximateCost() int

ApproximateCost estimates how much the mosaic will cost to build, given the price information embedded in the pieces. Returns a value in cents.

func (Inventory) DescendingUsage

func (inventory Inventory) DescendingUsage() []ColorUsage

func (Inventory) PiecesForColor

func (inv Inventory) PiecesForColor(c BrickColor) []Brick

func (Inventory) UsageForColorMap

func (inventory Inventory) UsageForColorMap() map[BrickColor]Usage

type LDU

type LDU int

All measurements are in terms of LDU

const (
	BrickWidth   LDU = 20
	BrickHeight  LDU = 24
	PlateHeight  LDU = 8
	StudDiameter LDU = 12
	StudHeight   LDU = 4
)

type Location

type Location struct {
	Row, Col int
}

Location represents one cell in the grid.

func Translate

func Translate(locs []Location, pt AnchorPoint) []Location

func TranslateAbsoluteOrigin

func TranslateAbsoluteOrigin(absLoc Location, p MosaicPiece, pt AnchorPoint) Location

func (Location) Add

func (loc Location) Add(loc2 Location) Location

Add adds one location to another (vector addition).

type MosaicPiece

type MosaicPiece interface {
	Brick
	Piece
	Rows() int
	Cols() int
}

MosaicPiece represents a given physical brick in a certain orientation, which determines its extent in the 2d grid.

func PiecesForOrientation

func PiecesForOrientation(o ViewOrientation, pieces []Brick) []MosaicPiece

func StudsOutPiece

func StudsOutPiece(piece Brick) MosaicPiece

TODO(ndunn): This could either be facing horizontally or vertically. This is not taking that into consideration.

func StudsRightPiece

func StudsRightPiece(piece Brick) MosaicPiece

func StudsTopPiece

func StudsTopPiece(piece Brick) MosaicPiece

type Piece

type Piece interface {
	Extent() []Location
}

Piece is the virtual representation of a physical brick. By abstracting out the orientation of the brick in real world space, it allows us to use the same algorithm for creating mosaics (solving grids) in any orientation.

For instance, say that we have a physical 2x4 brick. Depending on which way we orient the brick, it has different dimensions in the grid. If it is placed studs up, it is 3 plates (3 rows) high and 4 studs (4 columns) wide. This would be represented by a RectPiece with 3 rows and 4 columns, and its extent would be given by (0, 0), (0, 1), (0, 2), (0, 3) (1, 0), (1, 1), (1, 2), (1, 3) (2, 0), (2, 1), (2, 2), (2, 3).

In picture form:

+--+   +--+   +--+   +--+

+--+--+---+--+---+--+-- +--+--+ + | | | | | | | | | 3 plates high | | | | | | | | | +-----------------------------+ +

+-----------------------------+

4 studs wide

Say that we instead are looking down on the brick and building our mosaics that way, with the studs facing out towards the viewer. We can orient this in two directions - vertically or horizontally. In the vertical case, we would say that the Piece has 4 rows (4 studs) and 2 columns (2 studs).

+--------------+
|              |
| +--+    +--+ |
| |  |    |  | |
| +--+    +--+ |
|              |
| +--+    +--+ |
| |  |    |  | |
| +--+    +--+ |
|              |
| +--+    +--+ |
| |  |    |  | |
| +--+    +--+ |
|              |
| +--+    +--+ |
| |  |    |  | |
| +--+    +--+ |
|              |
+--------------+

In the horizontal case it's 2 rows (2 studs) and 4 columns (4 studs).

Note that the physical meaning of the dimension of each cell in the grid is dependent upon the orientation of the pieces, but completely unnecessary in the algorithm of filling in the pieces.

http://www.asciiflow.com/#Draw6066488077853425315/674394801

type PlacedBrick

type PlacedBrick struct {
	// Unique identifier for this brick within the mosaic
	Id int
	// Upper left corner of the piece
	Origin Location
	// The relative locations of how big this brick is. Add to origin to get absolute
	// location
	Locs []Location
	// What color is this brick?
	Color BrickColor
	// Characteristics of the brick - 2x4, etc
	Shape Brick
	// Orientation represents how the brick is placed in the mosaic
	Orientation ViewOrientation
}

PlacedBrick represents a physical brick placed within the mosaic, at a certain location, with a certain color, orientation, and shape.

func (PlacedBrick) Extent

func (p PlacedBrick) Extent() []Location

type Plan

type Plan interface {
	Orig() Ideal
	Pieces() []PlacedBrick
	Piece(row, col int) PlacedBrick
	Inventory() Inventory
}

Plan represents how to build the mosaic. The resulting plan may not match the Ideal perfectly; for instance, an implementation might decide to depart slightly from the desired colors if it leads to enhanced rigidity in the structure.

func CreateGridMosaic

func CreateGridMosaic(m Ideal, solver GridSolver) Plan

CreateGridMosaic converts an Ideal representation of the mosaic into a plan for building the mosaic. In other words, it picks the pieces to use and where to place them according to the logic in the GridSolver implementation.

type Posterize

type Posterize func(img image.Image, p color.Palette, rows int, cols int, o ViewOrientation) IdealImage

Posterize is the interface for converting from images into DesiredMosaic objects.

type QuantizationError

type QuantizationError struct {
	// contains filtered or unexported fields
}

QuantizationError represents an error between a desired color and the best possible color that we can use to represent it.

func Error

func Error(oldC, newC color.Color) QuantizationError

Error returns how much error is there from c1 relative to c0? High numbers means c1 has higher in that channel.

func (QuantizationError) Scale

Scale scales the given error by the given factor. For instance, Scale(2.0) doubles the error, while Scale(.5) halves it. This returns a new object.

type RectPiece

type RectPiece struct {
	NumRows int
	NumCols int
}

RectPiece represents a rectangular piece.

func (RectPiece) Extent

func (r RectPiece) Extent() []Location

type Renderer

type Renderer interface {
	Render(p Plan) string
}

Renderers somehow convert the plan into a form that's easy for humans to build. For instance it might render the plan as an SVG file embedded in a webpage, or print it to standard out, or render it as LDRAW instructions.

type SVGRenderer

type SVGRenderer struct{}

func (SVGRenderer) Render

func (r SVGRenderer) Render(p Plan) string

type Solution

type Solution struct {
	Original Grid
	Pieces   map[Location]MosaicPiece
}

Solution encapsulates the original requested grid to solve, as well as the solution to that grid, mapping location to the brick that goes there.

func GreedySolve

func GreedySolve(g *Grid, pieces []MosaicPiece) (Solution, error)

Solve attempts to solve the grid by filling in the missing pieces. The pieces are considered in the order defined in the pieces list. They should be sorted accordingly, with the best entry first in the list (i.e.. least expensive). If the given pieces cannot exactly match the missing pieces, returns a non nil error

func SymmetricalGreedySolve

func SymmetricalGreedySolve(g *Grid, pieces []MosaicPiece) (Solution, error)

func (Solution) String

func (solution Solution) String() string

TODO(ndunn): Remove, not very necessary given the mosaic rendering in svg

type State

type State int

State is an enum representing the state of a location in the grid.

const (
	// Empty indicates that nothing is in the grid location, nor should there be.
	Empty State = iota
	// ToBeFilled indicates that there is nothing currently in the grid location, but there should be.
	ToBeFilled State = Empty + 1
	// Filled indicates that there is already something in the grid location.
	Filled State = ToBeFilled + 1
)

type Usage

type Usage struct {
	NumPieces int
}

type ViewOrientation

type ViewOrientation int

ViewOrientation represents the orientation of each brick in the mosaic.

const (
	// StudsOut is a top down view, studs facing out towards viewer. Rows and columns refer to equal distances.
	StudsOut ViewOrientation = iota
	// StudsTop indicates a view from the side - pieces build on top of each other. Rows refer to plate height,
	// columns are 1x1 width.
	StudsTop
	// StudsRight indicates a view from the side, where the top of a piece faces to the right. Rows refer to
	// piece width, columns are plate height.
	StudsRight
)

type WriterRenderer

type WriterRenderer struct {
	// contains filtered or unexported fields
}

TerminalRenderer is an implementation of the Renderer interface which emits a textual representation of the Plan to stdout.

func (*WriterRenderer) Render

func (t *WriterRenderer) Render(p Plan) string

Directories

Path Synopsis
main runs the mosaic program.
main runs the mosaic program.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL