line_styling uz master pirms 4 mēnešiem
| @@ -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 | ||||
| @@ -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 | ||||
| } | } | ||||
| @@ -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) | ||||
| @@ -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, | |||||
| } | |||||
| } | |||||
| @@ -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)) | ||||
| @@ -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 | ||||