summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pgf/graphdrawing/lua/pgf/gd/lib/Bezier.lua
blob: e4fe21d9422c22cfcacd03a931c250c615a24bf4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
-- Copyright 2013 by Till Tantau
--
-- This file may be distributed an/or modified
--
-- 1. under the LaTeX Project Public License and/or
-- 2. under the GNU Public License
--
-- See the file doc/generic/pgf/licenses/LICENSE for more information

-- @release $Header$



---
-- This library offers a number of methods for working with Bezi\'er
-- curves.

local Bezier = {}

-- Namespace
require("pgf.gd.lib").Bezier = Bezier


-- Imports

local Coordinate = require 'pgf.gd.model.Coordinate'


---
-- Compute a point ``along a curve at a time''. You provide the four
-- coordinates of the curve and a time. You get a point on the curve
-- as return value as well as the two support vector for curve
-- before this point and two support vectors for the curve after the
-- point.
--
-- For speed reasons and in order to avoid superfluous creation of
-- lots of tables, all values are provided and returned as pairs of
-- values rather than as |Coordinate| objects.
--
-- @param ax The coordinate where the curve starts.
-- @param ay
-- @param bx The first support point.
-- @param by
-- @param cx The second support point.
-- @param cy
-- @param dx The coordinate where the curve ends.
-- @param dy
-- @param t A time (a number).
--
-- @return The point |p| on the curve at time |t| ($x$-part).
-- @return The point |p| on the curve at time |t| ($y$-part).
-- @return The first support point of the curve between |a| and |p| ($x$-part).
-- @return The first support point of the curve between |a| and |p| ($y$-part).
-- @return The second support point of the curve between |a| and |p| ($x$-part).
-- @return The second support point of the curve between |a| and |p| ($y$-part).
-- @return The first support point of the curve between |p| and |d| ($x$-part).
-- @return The first support point of the curve between |p| and |d| ($y$-part).
-- @return The second support point of the curve between |p| and |d| ($x$-part).
-- @return The second support point of the curve between |p| and |d| ($y$-part).

function Bezier.atTime(ax,ay,bx,by,cx,cy,dx,dy,t)

  local s = 1-t

  local ex, ey = ax*s + bx*t, ay*s + by*t
  local fx, fy = bx*s + cx*t, by*s + cy*t
  local gx, gy = cx*s + dx*t, cy*s + dy*t

  local hx, hy = ex*s + fx*t, ey*s + fy*t
  local ix, iy = fx*s + gx*t, fy*s + gy*t

  local jx, jy = hx*s + ix*t, hy*s + iy*t

  return jx, jy, ex, ey, hx, hy, ix, iy, gx, gy
end


---
-- The ``coordinate version'' of the |atTime| function, where both the
-- parameters and the return values are coordinate objects.

function Bezier.atTimeCoordinates(a,b,c,d,t)
  local jx, jy, ex, ey, hx, hy, ix, iy, gx, gy =
    Bezier.atTime(a.x,a.y,b.x,b.y,c.x,c.y,d.x,d.y,t)

  return
    Coordinate.new(jx, jy),
    Coordinate.new(ex, ey),
    Coordinate.new(hx, hy),
    Coordinate.new(ix, iy),
    Coordinate.new(gx, gy)
end


---
-- Computes the support points of a Bezier curve based on two points
-- on the curves at certain times.
--
-- @param from The start point of the curve
-- @param p1 A first point on the curve
-- @param t1 A time when this point should be reached
-- @param p2 A second point of the curve
-- @param t2 A time when this second point should be reached
-- @param to The end of the curve
--
-- @return sup1 A first support point of the curve
-- @return sup2 A second support point of the curve

function Bezier.supportsForPointsAtTime(from, p1, t1, p2, t2, to)

  local s1 = 1 - t1
  local s2 = 1 - t2

  local f1a = s1^3
  local f1b = t1 * s1^2 * 3
  local f1c = t1^2 * s1 * 3
  local f1d = t1^3

  local f2a = s2^3
  local f2b = t2 * s2^2 * 3
  local f2c = t2^2 * s2 * 3
  local f2d = t2^3

  -- The system:
  -- p1.x - from.x * f1a - to.x * f1d = sup1.x * f1b + sup2.x * f1c
  -- p2.x - from.x * f2a - to.x * f2d = sup1.x * f2b + sup2.x * f2c
  --
  -- p1.y - from.y * f1a - to.y * f1d = sup1.y * f1b + sup2.y * f1c
  -- p2.y - from.y * f2a - to.y * f2d = sup1.y * f2b + sup2.y * f2c

  local a = f1b
  local b = f1c
  local c = p1.x - from.x * f1a - to.x * f1d
  local d = f2b
  local e = f2c
  local f = p2.x - from.x * f2a - to.x * f2d

  local det = a*e - b*d
  local x1 = -(b*f - e*c)/det
  local x2 = -(c*d - a*f)/det

  local c = p1.y - from.y * f1a - to.y * f1d
  local f = p2.y - from.y * f2a - to.y * f2d

  local det = a*e - b*d
  local y1 = -(b*f - e*c)/det
  local y2 = -(c*d - a*f)/det

  return Coordinate.new(x1,y1), Coordinate.new(x2,y2)

end






-- Done

return Bezier