Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

88 linhas
2.1KB

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