diff --git a/.golangci.yml b/.golangci.yml index 0d46f05..e29c38b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -6,10 +6,9 @@ linters: - nlreturn # covered by wsl cuddle rules - nonamedreturns # named returns are accepted - mnd - - gomnd # deprecated - exhaustruct - - execinquery + - tenv severity: default-severity: major diff --git a/pkg/pattern/path/path.go b/pkg/pattern/path/path.go index 36b2d7b..647723e 100644 --- a/pkg/pattern/path/path.go +++ b/pkg/pattern/path/path.go @@ -2,33 +2,25 @@ package path import ( - "image/color" - "git.wtrh.nl/patterns/gopatterns/pkg/pattern/point" "github.com/tdewolff/canvas" ) // Path defines a set of straight lines through points. type Path struct { - points []point.Point - thickness float64 - color color.RGBA + points []point.Point + style Style } // NewPath returns a new [Path]. -func NewPath(points ...point.Point) *Path { - black := canvas.Black - return &Path{points: points, color: black, thickness: 0.2} -} - -// NewPathWithStyle returns a new [Path] with the specified thickness and color. -func NewPathWithStyle(thickness float64, color color.RGBA, points ...point.Point) Path { - return Path{points: points, color: color, thickness: thickness} +func NewPath(points []point.Point, style Style) *Path { + return &Path{points: points, style: style} } -// SetThickness updates the tickness of the line -func (p *Path) SetThickness(thickness float64) { - p.thickness = thickness +// WithStyle updates the style of the Path. +func (p *Path) WithStyle(Style Style) *Path { + p.style = Style + return p } // Draw the path to the provided [canvas.Canvas]. @@ -38,17 +30,7 @@ func (p *Path) Draw(c *canvas.Canvas) error { polyline.Add(next.Vector().Values()) } - c.RenderPath(polyline.ToPath(), - canvas.Style{ - Fill: canvas.Paint{}, - Stroke: canvas.Paint{Color: p.color}, - StrokeWidth: p.thickness, - StrokeCapper: canvas.RoundCap, - StrokeJoiner: canvas.BevelJoin, - DashOffset: 0, - Dashes: nil, - FillRule: 0, - }, canvas.Identity) + c.RenderPath(polyline.ToPath(), p.style.ToCanvas(), canvas.Identity) return nil } diff --git a/pkg/pattern/path/splines.go b/pkg/pattern/path/splines.go index 92cf81c..8f1f1fa 100644 --- a/pkg/pattern/path/splines.go +++ b/pkg/pattern/path/splines.go @@ -2,7 +2,6 @@ package path import ( "fmt" - "git.wtrh.nl/patterns/gopatterns/pkg/pattern/point" "github.com/tdewolff/canvas" splines "gitlab.com/Achilleshiel/gosplines" @@ -16,42 +15,48 @@ type Spline struct { start, end point.Point } +type SplineOpts struct { + Start, End point.Point + Points []point.Point + Style Style +} + // NewSpline returns a new spline through points. Start and end points can be provided as // the start and stop direction of the spline. When start or end point arguments are left nil there // are no constraints on the direction. -func NewSpline(start, end point.Point, points ...point.Point) Spline { +func NewSpline(opts SplineOpts) Spline { s := Spline{ - Path: NewPath(points...), - start: start, - end: end, + Path: NewPath(opts.Points, opts.Style), + start: opts.Start, + end: opts.End, } - if start == nil && len(points) > 1 { - s.start = points[0] + if opts.Start == nil && len(opts.Points) > 1 { + s.start = opts.Points[0] } - if end == nil && len(points) > 1 { - s.end = points[len(points)-1] + if opts.End == nil && len(opts.Points) > 1 { + s.end = opts.Points[len(opts.Points)-1] } return s } // Draw the spline to the provided [canvas.Canvas]. -func (p Spline) Draw(c *canvas.Canvas) error { - if len(p.points) < 2 { +func (s Spline) Draw(c *canvas.Canvas) error { + if len(s.points) < 2 { return nil } - x := make([]float64, len(p.points)) - y := make([]float64, len(p.points)) + x := make([]float64, len(s.points)) + y := make([]float64, len(s.points)) - for i, point := range p.points { - x[i], y[i] = point.Vector().Values() + for i, p := range s.points { + x[i], y[i] = p.Vector().Values() } - diffStart := p.start.Vector().Subtract(p.points[0].Vector()) - diffEnd := p.points[len(p.points)-1].Vector().Subtract(p.end.Vector()) + diffStart := s.start.Vector().Subtract(s.points[0].Vector()) + diffEnd := s.points[len(s.points)-1].Vector().Subtract(s.end.Vector()) xCoefficient, err := splines.SolveSplineWithConstraint(x, diffStart.X, diffEnd.X) if err != nil { @@ -66,8 +71,8 @@ func (p Spline) Draw(c *canvas.Canvas) error { points := make([]point.Point, 0, len(x)*resolution) stepSize := 1.0 / float64(resolution-1) - for i := range len(p.points) - 1 { - points = append(points, p.points[i]) + for i := range len(s.points) - 1 { + points = append(points, s.points[i]) for t := stepSize; t < 1.0; t += stepSize { xCalculated := xCoefficient[i].Calculate(t) @@ -76,10 +81,9 @@ func (p Spline) Draw(c *canvas.Canvas) error { } } - points = append(points, p.points[len(p.points)-1]) + points = append(points, s.points[len(s.points)-1]) - path := NewPath(points...) - path.SetThickness(p.thickness) + path := NewPath(points, s.style) if err = path.Draw(c); err != nil { return fmt.Errorf("draw spline points to canvas: %w", err) diff --git a/pkg/pattern/path/style.go b/pkg/pattern/path/style.go new file mode 100644 index 0000000..b430870 --- /dev/null +++ b/pkg/pattern/path/style.go @@ -0,0 +1,33 @@ +package path + +import ( + "image/color" + + "github.com/tdewolff/canvas" +) + +type Style struct { + Thickness float64 + Color color.RGBA + Dashes []float64 +} + +func (s Style) ToCanvas() canvas.Style { + return canvas.Style{ + Fill: canvas.Paint{}, + Stroke: canvas.Paint{Color: s.Color}, + StrokeWidth: s.Thickness, + StrokeCapper: canvas.RoundCap, + StrokeJoiner: canvas.BevelJoin, + DashOffset: 0, + Dashes: s.Dashes, + FillRule: 0, + } +} + +func NewDefaultStyle() Style { + return Style{ + Thickness: 0.2, + Color: canvas.Black, + } +} diff --git a/pkg/pattern/pattern.go b/pkg/pattern/pattern.go index 3d1ac70..e066893 100644 --- a/pkg/pattern/pattern.go +++ b/pkg/pattern/pattern.go @@ -11,7 +11,7 @@ import ( "gopkg.in/Knetic/govaluate.v3" ) -// Pattern contains all the points, lines and dimensions to draw a pattern to a canvas. +// The Pattern contains all the points, lines and dimensions to draw a pattern to a canvas. type Pattern struct { points map[point.ID]point.Point lines []pathDrawer @@ -34,7 +34,7 @@ func (p *Pattern) AddLine(line pathDrawer) { } // GetPoints returns a slice with points for the given IDs. -func (p *Pattern) GetPoints(id ...point.ID) []point.Point { +func (p *Pattern) GetPoints(id []point.ID) []point.Point { points := make([]point.Point, 0, len(id)) for _, i := range id { points = append(points, p.GetPoint(i)) diff --git a/pkg/pattern/template/line.go b/pkg/pattern/template/line.go index 1a10083..1c7c21d 100644 --- a/pkg/pattern/template/line.go +++ b/pkg/pattern/template/line.go @@ -28,29 +28,29 @@ type Curve struct { // Build adds the line to the provided [pattern.Pattern]. func (l Line) Build(pat *pattern.Pattern) error { - points := pat.GetPoints(l.Through...) + points := pat.GetPoints(l.Through) for _, p := range points { p.SetDraw() } - switch { - case l.Curve != nil: - startPoint := pat.GetPoint(l.Curve.Start) - endPoint := pat.GetPoint(l.Curve.End) - spline := path.NewSpline(startPoint, endPoint, points...) + style := path.NewDefaultStyle() - if l.Style != nil && l.Style.Thickness != nil { - spline.SetThickness(*l.Style.Thickness) - } + if l.Style != nil && l.Style.Thickness != nil { + style.Thickness = *l.Style.Thickness + } - pat.AddLine(spline) + switch { + case l.Curve != nil: + pat.AddLine( + path.NewSpline(path.SplineOpts{ + Start: pat.GetPoint(l.Curve.Start), + End: pat.GetPoint(l.Curve.End), + Points: points, + Style: style, + }), + ) default: - newPath := path.NewPath(points...) - if l.Style != nil && l.Style.Thickness != nil { - newPath.SetThickness(*l.Style.Thickness) - } - - pat.AddLine(newPath) + pat.AddLine(path.NewPath(points, style)) } return nil