8f982278d2
* add multimodule * re-package modules
77 lines
2.2 KiB
Go
77 lines
2.2 KiB
Go
package plotter
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"math"
|
|
"math/rand"
|
|
|
|
"github.com/iliadenisov/galaxy/server/internal/bitmap"
|
|
)
|
|
|
|
type Plotter struct {
|
|
factor float64
|
|
clearFn func()
|
|
circleFn func(x, y int, r float64)
|
|
freeCountFn func() int
|
|
freeNumberToCoordFn func(int) (int, int, error)
|
|
}
|
|
|
|
func NewPlotter(width, height uint32, factor float64) (Plotter, error) {
|
|
return NewBitmapPlotter(NewBitmap(width, height, factor), factor)
|
|
}
|
|
|
|
func NewBitmap(width, height uint32, factor float64) bitmap.Bitmap {
|
|
return bitmap.NewBitmap(AsPlotterSize(width, height, factor))
|
|
}
|
|
|
|
func NewBitmapPlotter(bm bitmap.Bitmap, factor float64) (Plotter, error) {
|
|
if factor > 1 || factor <= 0 {
|
|
return Plotter{}, fmt.Errorf("factor should be: 0 > F <= 1")
|
|
}
|
|
return Plotter{
|
|
factor: factor,
|
|
clearFn: bm.Clear,
|
|
circleFn: func(x, y int, r float64) { bm.Circle(x, y, r, true) },
|
|
freeCountFn: bm.FreeCount,
|
|
freeNumberToCoordFn: bm.GetFreeN,
|
|
}, nil
|
|
}
|
|
|
|
func (p Plotter) RandomFreePoint(deadZoneRaduis float64) (float64, float64, error) {
|
|
fsCount := p.freeCountFn()
|
|
if fsCount == 0 {
|
|
return 0, 0, errors.New("RandomFreePoint: no free space left")
|
|
}
|
|
next := rand.Intn(fsCount)
|
|
x, y, err := p.freeNumberToCoordFn(next)
|
|
if err != nil {
|
|
return 0, 0, fmt.Errorf("RandomFreePoint: freeNumberToCoordFn: %s", err)
|
|
}
|
|
if deadZoneRaduis > 0 {
|
|
p.plotDeadZone(x, y, deadZoneRaduis)
|
|
}
|
|
planetX := float64(x)*p.factor + rand.Float64()*p.factor
|
|
planetY := float64(y)*p.factor + rand.Float64()*p.factor
|
|
return planetX, planetY, nil
|
|
}
|
|
|
|
func (p Plotter) MarkDeadZone(x, y float64, radius float64) {
|
|
p.plotDeadZone(int(x/p.factor), int(y/p.factor), radius)
|
|
}
|
|
|
|
func (p Plotter) plotDeadZone(x, y int, radius float64) {
|
|
// Adding extra 'pixel' to avoid radius became less than deadZoneRaduis
|
|
// after division by factor due to floating-point operations specifics
|
|
p.circleFn(x, y, (radius+p.factor)/p.factor)
|
|
}
|
|
|
|
func (p Plotter) Clear() { p.clearFn() }
|
|
|
|
func AsPlotterSize(width, height uint32, factor float64) (uint32, uint32) {
|
|
if factor > 1 || factor <= 0 {
|
|
return width, height
|
|
}
|
|
return uint32(math.Ceil(float64(width) / float64(factor))), uint32(math.Ceil(float64(height) / float64(factor)))
|
|
}
|