lambdaway
::
bezier
2
|
list
|
login
|
load
|
|
{div {@ style="position:relative; height:700px; box-shadow:0 0 8px #000; background:#888;"} {S.map {lambda {:t} {dot {bezier {BZ1} :t} 5 #0ff}} {S.serie -0.1 1.2 0.02}} {S.map {lambda {:t} {dot {bezier {BZ2} :t} 5 #ff0}} {S.serie -0.1 1.2 0.02}} {dot {Q0} 20 #ff000088} {dot {Q1} 20 #ff000088} {dot {Q2} 20 #ff000088} {dot {Q3} 20 #ff000088} } {center ¡ vamos a bailar la lambdada !} _h1 a bezier curve | [[bezier_2]] _p See [[beziers|https://news.ycombinator.com/item?id=30100427]] _p Drawing a cubic bezier curve out of any SVG or CANVAS frame. _h2 1) interpolating 4 points _p The Bézier curve is defined as an array of 4 given control points, each defined as an array of 2 numbers. The {code bezier} function returns the point interpolating the 4 points, given a value t in [t0,t1]. {center {pre P(t) = (1-t){sup 3}P{sub 0} + 3(1-t){sup 2}tP{sub 1} + 3(1-t)t{sup 2}P{sub 2} + t{sup 3}P{sub 3}}} {prewrap '{def bezier // interpolate 4 points {def bezier.interpol // interpolate 4 numbers {lambda {:a0 :a1 :a2 :a3 :t :u} {round {+ {* :a0 :u :u :u 1} // 1 * (1-t)^3 * a0 {* :a1 :u :u :t 3} // 3 * (1-t)^2 * t * a1 {* :a2 :u :t :t 3} // 3 * (1-t) * t^2 * a2 {* :a3 :t :t :t 1}}}}} // 1 * t^3 * a3 {lambda {:bz :t} // return the interpolated point {A.new {bezier.interpol {A.get 0 {A.get 0 :bz}} {A.get 0 {A.get 1 :bz}} {A.get 0 {A.get 2 :bz}} {A.get 0 {A.get 3 :bz}} :t {- 1 :t}} {bezier.interpol {A.get 1 {A.get 0 :bz}} {A.get 1 {A.get 1 :bz}} {A.get 1 {A.get 2 :bz}} {A.get 1 {A.get 3 :bz}} :t {- 1 :t}}} }} -> {def bezier {def bezier.interpol {lambda {:a0 :a1 :a2 :a3 :t :u} {round {+ {* :a0 :u :u :u 1} {* :a1 :u :u :t 3} {* :a2 :u :t :t 3} {* :a3 :t :t :t 1}}}}} {lambda {:bz :t} {A.new {bezier.interpol {A.get 0 {A.get 0 :bz}} {A.get 0 {A.get 1 :bz}} {A.get 0 {A.get 2 :bz}} {A.get 0 {A.get 3 :bz}} :t {- 1 :t}} {bezier.interpol {A.get 1 {A.get 0 :bz}} {A.get 1 {A.get 1 :bz}} {A.get 1 {A.get 2 :bz}} {A.get 1 {A.get 3 :bz}} :t {- 1 :t}}} }} } _h2 2) plotting a dot _p We don't draw in any SVG or CANVAS frame, but directly in the HTML page, using {code div} HTML blocks designed as colored circles. {pre '{def dot {lambda {:p :r :col} {div {@ style="position:absolute; // it's just HTML and CSS left: {- {A.get 0 :p} {/ :r 2}}px; top: {- {A.get 1 :p} {/ :r 2}}px; width: :rpx; height: :rpx; border-radius: :rpx; border: 1px solid #000; background: :col;"}[{A.get 0 :p},{A.get 1 :p}]}}} -> {def dot {lambda {:p :r :col} {div {@ style="position:absolute; left: {- {A.get 0 :p} {/ :r 2}}px; top: {- {A.get 1 :p} {/ :r 2}}px; width: :rpx; height: :rpx; border-radius: :rpx; border: 1px solid #000; background: :col;"} [{A.get 0 :p},{A.get 1 :p}]}}} } _h2 3) defining 4 control points {pre '{def Q0 {A.new 150 150}} -> {def Q0 {A.new 150 150}} '{def Q1 {A.new 500 300}} -> {def Q1 {A.new 500 300}} '{def Q2 {A.new 100 500}} -> {def Q2 {A.new 100 500}} '{def Q3 {A.new 300 500}} -> {def Q3 {A.new 300 500}} } _h2 4) defining 2 curves _p We use the same control points but in different orders to define two curves {pre '{def BZ1 {A.new {Q0} {Q1} {Q2} {Q3}}} -> {def BZ1 {A.new {Q0} {Q1} {Q2} {Q3}}} '{def BZ2 {A.new {Q0} {Q2} {Q1} {Q3}}} -> {def BZ2 {A.new {Q0} {Q2} {Q1} {Q3}}} } _h2 5) drawing 2 curves and 4 dots _p We {b map} the {code bezier} function on a {b serie} of values from -0.1 to 1.2 with step 0.02. {pre '{S.map {lambda {:t} {dot {bezier {BZ1} :t} 5 red}} {S.serie -0.1 1.2 0.02}} '{S.map {lambda {:t} {dot {bezier {BZ2} :t} 5 blue}} {S.serie -0.1 1.2 0.02}} '{dot {Q0} 20 cyan} '{dot {Q1} 20 cyan} '{dot {Q2} 20 cyan} '{dot {Q3} 20 cyan} } _p which are displayed at the top of this page. _p A more "serious" and efficient approoach can be seen in [[decasteljau]].
lambdaway v.20211111