feat: primitive styling

This commit is contained in:
IliaDenisov
2026-03-07 17:01:22 +02:00
parent 477e656008
commit e4b956232f
18 changed files with 1264 additions and 175 deletions
+99 -9
View File
@@ -21,6 +21,7 @@ type World struct {
rows, cols int
objects map[uuid.UUID]MapItem
renderState rendererIncrementalState
styles *StyleTable
}
// NewWorld constructs a new world with the given real dimensions.
@@ -34,6 +35,7 @@ func NewWorld(width, height int) *World {
H: height * SCALE,
cellSize: 1,
objects: make(map[uuid.UUID]MapItem),
styles: NewStyleTable(),
}
}
@@ -46,46 +48,88 @@ func (g *World) checkCoordinate(xf, yf int) bool {
return true
}
// AddStyleLine creates a new line style derived from the default line style.
func (g *World) AddStyleLine(override StyleOverride) StyleID {
return g.styles.AddDerived(StyleIDDefaultLine, override)
}
// AddStyleCircle creates a new circle style derived from the default circle style.
func (g *World) AddStyleCircle(override StyleOverride) StyleID {
return g.styles.AddDerived(StyleIDDefaultCircle, override)
}
// AddStylePoint creates a new point style derived from the default point style.
func (g *World) AddStylePoint(override StyleOverride) StyleID {
return g.styles.AddDerived(StyleIDDefaultPoint, override)
}
// AddPoint validates and stores a point primitive in the world.
// The input coordinates are given in real world units and are converted
// to fixed-point before validation.
func (g *World) AddPoint(x, y float64) (uuid.UUID, error) {
func (g *World) AddPoint(x, y float64, opts ...PointOpt) (uuid.UUID, error) {
xf := fixedPoint(x)
yf := fixedPoint(y)
if ok := g.checkCoordinate(xf, yf); !ok {
return uuid.Nil, errBadCoordinate
}
o := defaultPointOptions()
for _, opt := range opts {
if opt != nil {
opt(&o)
}
}
styleID := g.resolvePointStyleID(o)
id := uuid.New()
g.objects[id] = Point{Id: id, X: xf, Y: yf}
g.objects[id] = Point{
Id: id,
X: xf,
Y: yf,
Priority: o.Priority,
StyleID: styleID,
}
return id, nil
}
// AddCircle validates and stores a circle primitive in the world.
// The center and radius are given in real world units and are converted
// to fixed-point before validation. A zero radius is allowed.
func (g *World) AddCircle(x, y, r float64) (uuid.UUID, error) {
func (g *World) AddCircle(x, y, r float64, opts ...CircleOpt) (uuid.UUID, error) {
xf := fixedPoint(x)
yf := fixedPoint(y)
rf := fixedPoint(r)
if ok := g.checkCoordinate(xf, yf); !ok {
return uuid.Nil, errBadCoordinate
}
if rf < 0 {
if r < 0 {
return uuid.Nil, errBadRadius
}
o := defaultCircleOptions()
for _, opt := range opts {
if opt != nil {
opt(&o)
}
}
styleID := g.resolveCircleStyleID(o)
id := uuid.New()
g.objects[id] = Circle{Id: id, X: xf, Y: yf, Radius: rf}
g.objects[id] = Circle{
Id: id,
X: xf,
Y: yf,
Radius: fixedPoint(r),
Priority: o.Priority,
StyleID: styleID,
}
return id, nil
}
// AddLine validates and stores a line primitive in the world.
// The endpoints are given in real world units and are converted
// to fixed-point before validation.
func (g *World) AddLine(x1, y1, x2, y2 float64) (uuid.UUID, error) {
func (g *World) AddLine(x1, y1, x2, y2 float64, opts ...LineOpt) (uuid.UUID, error) {
x1f := fixedPoint(x1)
y1f := fixedPoint(y1)
x2f := fixedPoint(x2)
@@ -98,11 +142,57 @@ func (g *World) AddLine(x1, y1, x2, y2 float64) (uuid.UUID, error) {
return uuid.Nil, errBadCoordinate
}
o := defaultLineOptions()
for _, opt := range opts {
if opt != nil {
opt(&o)
}
}
styleID := g.resolveLineStyleID(o)
id := uuid.New()
g.objects[id] = Line{Id: id, X1: x1f, Y1: y1f, X2: x2f, Y2: y2f}
g.objects[id] = Line{
Id: id,
X1: x1f,
Y1: y1f,
X2: x2f,
Y2: y2f,
Priority: o.Priority,
StyleID: styleID,
}
return id, nil
}
func (g *World) resolvePointStyleID(o PointOptions) StyleID {
if o.hasStyleID {
return o.StyleID
}
if o.Override.IsZero() {
return StyleIDDefaultPoint
}
return g.styles.AddDerived(StyleIDDefaultPoint, o.Override)
}
func (g *World) resolveCircleStyleID(o CircleOptions) StyleID {
if o.hasStyleID {
return o.StyleID
}
if o.Override.IsZero() {
return StyleIDDefaultCircle
}
return g.styles.AddDerived(StyleIDDefaultCircle, o.Override)
}
func (g *World) resolveLineStyleID(o LineOptions) StyleID {
if o.hasStyleID {
return o.StyleID
}
if o.Override.IsZero() {
return StyleIDDefaultLine
}
return g.styles.AddDerived(StyleIDDefaultLine, o.Override)
}
// worldToCellX converts a fixed-point X coordinate to a grid column index.
func (g *World) worldToCellX(x int) int {
return worldToCell(x, g.W, g.cols, g.cellSize)