Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

94 строки
2.3KB

  1. package path
  2. import (
  3. "fmt"
  4. "image/color"
  5. "git.wtrh.nl/patterns/gopatterns/pkg/pattern/point"
  6. "github.com/tdewolff/canvas"
  7. splines "gitlab.com/Achilleshiel/gosplines"
  8. )
  9. const resolution = 40
  10. // Spline defines a smooth curved path through points.
  11. type Spline struct {
  12. *Path
  13. start, end point.Point
  14. }
  15. // NewSpline returns a new spline through points. Start and end points can be provided as
  16. // the start and stop direction of the spline. When start or end point arguments are left nil there
  17. // are no constraints on the direction.
  18. func NewSpline(start, end point.Point, points []point.Point) Spline {
  19. s := Spline{
  20. Path: NewPath(points),
  21. start: start,
  22. end: end,
  23. }
  24. if start == nil && len(points) > 1 {
  25. s.start = points[0]
  26. }
  27. if end == nil && len(points) > 1 {
  28. s.end = points[len(points)-1]
  29. }
  30. return s
  31. }
  32. // Draw the spline to the provided [canvas.Canvas].
  33. func (p Spline) Draw(c *canvas.Canvas) error {
  34. if len(p.points) < 2 {
  35. return nil
  36. }
  37. x := make([]float64, len(p.points))
  38. y := make([]float64, len(p.points))
  39. for i, point := range p.points {
  40. x[i], y[i] = point.Vector().Values()
  41. }
  42. diffStart := p.start.Vector().Subtract(p.points[0].Vector())
  43. diffEnd := p.points[len(p.points)-1].Vector().Subtract(p.end.Vector())
  44. xCoefficient, err := splines.SolveSplineWithConstraint(x, diffStart.X, diffEnd.X)
  45. if err != nil {
  46. return fmt.Errorf("unable to calculate coefficients for x: %w", err)
  47. }
  48. yCoefficient, err := splines.SolveSplineWithConstraint(y, diffStart.Y, diffEnd.Y)
  49. if err != nil {
  50. return fmt.Errorf("unable to calculate coefficients for y: %w", err)
  51. }
  52. points := make([]point.Point, 0, len(x)*resolution)
  53. stepSize := 1.0 / float64(resolution-1)
  54. for i := range len(p.points) - 1 {
  55. points = append(points, p.points[i])
  56. for t := stepSize; t < 1.0; t += stepSize {
  57. xCalculated := xCoefficient[i].Calculate(t)
  58. yCalculated := yCoefficient[i].Calculate(t)
  59. points = append(points, point.NewAbsolutePoint(xCalculated, yCalculated, 0, "0"))
  60. }
  61. }
  62. points = append(points, p.points[len(p.points)-1])
  63. path := NewPath(points).WithStyle(Style{
  64. Thickness: p.Path.style.Thickness,
  65. Color: color.RGBA{},
  66. Dashes: nil,
  67. })
  68. if err = path.Draw(c); err != nil {
  69. return fmt.Errorf("draw spline points to canvas: %w", err)
  70. }
  71. return nil
  72. }