Browse Source

Refactor line styling

pull/7/head
Wouter Horlings 4 months ago
parent
commit
70ec8f7d70
6 changed files with 87 additions and 69 deletions
  1. +1
    -2
      .golangci.yml
  2. +9
    -27
      pkg/pattern/path/path.go
  3. +26
    -22
      pkg/pattern/path/splines.go
  4. +33
    -0
      pkg/pattern/path/style.go
  5. +2
    -2
      pkg/pattern/pattern.go
  6. +16
    -16
      pkg/pattern/template/line.go

+ 1
- 2
.golangci.yml View File

@@ -6,10 +6,9 @@ linters:
- nlreturn # covered by wsl cuddle rules - nlreturn # covered by wsl cuddle rules
- nonamedreturns # named returns are accepted - nonamedreturns # named returns are accepted
- mnd - mnd
- gomnd
# deprecated # deprecated
- exhaustruct - exhaustruct
- execinquery
- tenv


severity: severity:
default-severity: major default-severity: major


+ 9
- 27
pkg/pattern/path/path.go View File

@@ -2,33 +2,25 @@
package path package path


import ( import (
"image/color"

"git.wtrh.nl/patterns/gopatterns/pkg/pattern/point" "git.wtrh.nl/patterns/gopatterns/pkg/pattern/point"
"github.com/tdewolff/canvas" "github.com/tdewolff/canvas"
) )


// Path defines a set of straight lines through points. // Path defines a set of straight lines through points.
type Path struct { type Path struct {
points []point.Point
thickness float64
color color.RGBA
points []point.Point
style Style
} }


// NewPath returns a new [Path]. // 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]. // 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()) 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 return nil
} }

+ 26
- 22
pkg/pattern/path/splines.go View File

@@ -2,7 +2,6 @@ package path


import ( import (
"fmt" "fmt"

"git.wtrh.nl/patterns/gopatterns/pkg/pattern/point" "git.wtrh.nl/patterns/gopatterns/pkg/pattern/point"
"github.com/tdewolff/canvas" "github.com/tdewolff/canvas"
splines "gitlab.com/Achilleshiel/gosplines" splines "gitlab.com/Achilleshiel/gosplines"
@@ -16,42 +15,48 @@ type Spline struct {
start, end point.Point 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 // 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 // the start and stop direction of the spline. When start or end point arguments are left nil there
// are no constraints on the direction. // are no constraints on the direction.
func NewSpline(start, end point.Point, points ...point.Point) Spline {
func NewSpline(opts SplineOpts) Spline {
s := 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 return s
} }


// Draw the spline to the provided [canvas.Canvas]. // 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 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) xCoefficient, err := splines.SolveSplineWithConstraint(x, diffStart.X, diffEnd.X)
if err != nil { if err != nil {
@@ -66,8 +71,8 @@ func (p Spline) Draw(c *canvas.Canvas) error {
points := make([]point.Point, 0, len(x)*resolution) points := make([]point.Point, 0, len(x)*resolution)
stepSize := 1.0 / float64(resolution-1) 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 { for t := stepSize; t < 1.0; t += stepSize {
xCalculated := xCoefficient[i].Calculate(t) 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 { if err = path.Draw(c); err != nil {
return fmt.Errorf("draw spline points to canvas: %w", err) return fmt.Errorf("draw spline points to canvas: %w", err)


+ 33
- 0
pkg/pattern/path/style.go View File

@@ -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,
}
}

+ 2
- 2
pkg/pattern/pattern.go View File

@@ -11,7 +11,7 @@ import (
"gopkg.in/Knetic/govaluate.v3" "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 { type Pattern struct {
points map[point.ID]point.Point points map[point.ID]point.Point
lines []pathDrawer lines []pathDrawer
@@ -34,7 +34,7 @@ func (p *Pattern) AddLine(line pathDrawer) {
} }


// GetPoints returns a slice with points for the given IDs. // 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)) points := make([]point.Point, 0, len(id))
for _, i := range id { for _, i := range id {
points = append(points, p.GetPoint(i)) points = append(points, p.GetPoint(i))


+ 16
- 16
pkg/pattern/template/line.go View File

@@ -28,29 +28,29 @@ type Curve struct {


// Build adds the line to the provided [pattern.Pattern]. // Build adds the line to the provided [pattern.Pattern].
func (l Line) Build(pat *pattern.Pattern) error { func (l Line) Build(pat *pattern.Pattern) error {
points := pat.GetPoints(l.Through...)
points := pat.GetPoints(l.Through)
for _, p := range points { for _, p := range points {
p.SetDraw() 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: 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 return nil


Loading…
Cancel
Save