lambdaway
::
bezier_3
3
|
list
|
login
|
load
|
|
{center {svg {@ width="580" height="580" style="background:#444;"} {polyline {@ points="{curve {A.new {P0} {P20} {P2}} 20}" stroke="#f00" fill="transparent" stroke-width="4"}} {polyline {@ points="{curve {A.new {P1} {P01} {P0}} 20}" stroke="#0f0" fill="transparent" stroke-width="4"}} {polyline {@ points="{curve {A.new {P2} {P12} {P1}} 20}" stroke="#00f" fill="transparent" stroke-width="4"}} {dot {P0} 10 #fff} {dot {P1} 10 #fff} {dot {P2} 10 #fff} {dot {P02} 5 #ff0} {dot {P20} 7 #fff} {dot {P10} 5 #ff0} {dot {P01} 7 #fff} {dot {P21} 5 #ff0} {dot {P12} 7 #fff} }} _h1 [[a bezier curve|?view=bezier]] | [[bezier_2]] | bezier_3 _p We find a {b quadratic curve interpolating three points} using a bezier algorithm. _p We know that a bezier curve built on 3 points, {b p{sub 0}, p{sub 1}, p{sub 2}}, doesn't interpolate {b p{sub 1}}. We compute the middle of {b [p{sub 0}, p{sub 2}]}, {b p{sub 02}}, and its symetric, {b p{sub 20}}, with respect to {b p{sub 1}}. The curve built on {b p{sub 0}, p{sub 20}, p{sub 2}} interpolates {b p{sub 0}, p{sub 1}, p{sub 2}}. _h2 bezier interpolation of 3 points _p The vectorial expression of a point {b p(t)} interpolating three points, {b p{sub 0}, p{sub 1}, p{sub 2}}, {pre {center {b p}(t) = 1*{b p}{sub 0}(1-t){sup 2} + 2*{b p}{sub 1}(1-t)t + 1*{b p}{sub 2}t{sup 2} }} _p is translated into the {b interpol} function getting three arrays, {b [x,y]}, a value {b t} in the {b [0,1]} interval and returning a SVG sequence, {b "x y"}. {pre '{def interpol {lambda {:p0 :p1 :p2 :t :u} // u =1-t {+ {* 1 {A.get 0 :p0} :u :u} {* 2 {A.get 0 :p1} :u :t} {* 1 {A.get 0 :p2} :t :t}} {+ {* 1 {A.get 1 :p0} :u :u} {* 2 {A.get 1 :p1} :u :t} {* 1 {A.get 1 :p2} :t :t}} }} -> {def interpol {lambda {:p0 :p1 :p2 :t :u} {+ {* 1 {A.get 0 :p0} :u :u} {* 2 {A.get 0 :p1} :u :t} {* 1 {A.get 0 :p2} :t :t}} {+ {* 1 {A.get 1 :p0} :u :u} {* 2 {A.get 1 :p1} :u :t} {* 1 {A.get 1 :p2} :t :t}} }} } _h2 from bezier to spline _p The quadratic spline interpolating three points, {b p{sub 0}, p{sub 1}, p{sub 2}}, is the quadratic bezier curve, {b p{sub 0}, p{sub 20}, p{sub 2}}, where {b p{sub 20}} is the symetric of the point {b p{sub 02}}, middle of {b p{sub 0}, p{sub 2}}. {pre '{def middle {lambda {:p1 :p2} // compute the middle point of p1 and p2 {A.new {/ {+ {A.get 0 :p1} {A.get 0 :p2}} 2} {/ {+ {A.get 1 :p1} {A.get 1 :p2}} 2} }}} -> {def middle {lambda {:p1 :p2} {A.new {/ {+ {A.get 0 :p1} {A.get 0 :p2}} 2} {/ {+ {A.get 1 :p1} {A.get 1 :p2}} 2} }}} '{def symetric // compute the symmetric point of p1 with respect to p2 {lambda {:p1 :p2} {A.new {- {* 2 {A.get 0 :p2}} {A.get 0 :p1} } {- {* 2 {A.get 1 :p2}} {A.get 1 :p1} } }}} -> {def symetric {lambda {:p1 :p2} {A.new {- {* 2 {A.get 0 :p2}} {A.get 0 :p1} } {- {* 2 {A.get 1 :p2}} {A.get 1 :p1} } }}} } _h2 computing the curve _p The curve is approximated by a {b SVG polyline} built on {b n+1} points {b [0,n]}. In fact we we add a point ar {b -1} and at {b n+1} for a better graphical display. {pre '{def curve {lambda {:pol :n} {S.map {{lambda {:p0 :p1 :p2 :n :i} {interpol :p0 :p1 :p2 {/ :i :n} {- 1 {/ :i :n}}} } {A.get 0 :pol} {A.get 1 :pol} {A.get 2 :pol} :n} {S.serie -1 {+ :n 1}} }}} -> {def curve {lambda {:pol :n} {S.map {{lambda {:p0 :p1 :p2 :n :i} {interpol :p0 :p1 :p2 {/ :i :n} {- 1 {/ :i :n}}} } {A.get 0 :pol} {A.get 1 :pol} {A.get 2 :pol} :n} {S.serie -1 {+ :n 1}} }}} } _p The {b curve} function gets the three points arrays, {b pol}, a value {b n} and returns a SVG sequence, {b "x0 y0 x1 y1 x2 y2 ..."}. _h2 drawing a point _p A point is drawn as a small circle. {pre '{def dot {lambda {:pt :r :col} {circle {@ cx="{A.get 0 :pt}" cy="{A.get 1 :pt}" r="5" stroke="#000" fill=":col" stroke-width="2" opacity="0.5"}}}} -> {def dot {lambda {:pt :r :col} {circle {@ cx="{A.get 0 :pt}" cy="{A.get 1 :pt}" r=":r" stroke="#000" fill=":col" stroke-width="2" opacity="0.5"}}}} } _h2 defining points _p Points are given as arrays of two values {b [x,y]} {pre '{def P0 {A.new 150 200}} -> {def P0 {A.new 150 200}} '{def P1 {A.new 300 350}} -> {def P1 {A.new 300 350}} '{def P2 {A.new 150 370}} -> {def P2 {A.new 150 370}} } _p Computing middle points and their symetric points {pre '{def P02 {middle {P0} {P2}}} -> {def P02 {middle {P0} {P2}}} '{def P20 {symetric {P02} {P1}}} -> {def P20 {symetric {P02} {P1}}} '{def P10 {middle {P1} {P0}}} -> {def P10 {middle {P1} {P0}}} '{def P01 {symetric {P10} {P2}}} -> {def P01 {symetric {P10} {P2}}} '{def P21 {middle {P2} {P1}}} -> {def P21 {middle {P2} {P1}}} '{def P12 {symetric {P21} {P0}}} -> {def P12 {symetric {P21} {P0}}} } _h2 drawing points and curves _p The SVG polyline's {b points} attribute gets the sequence of {b x y} values given by the {b curve} function. We draw the three points, {b P0, P1, P2}, the three quadratic curves interpolating {b [P0, P1, P2]}, {b [P1, P2, P0]} and {b [P2, P0, P1]}, and the six points used in the translation from the bezier curve to the spline. {pre '{svg {@ width="500" height="500" style="background:#444;"} {polyline {@ points="{curve {A.new {P0} {P20} {P2}} 20}" stroke="#f00" fill="transparent" stroke-width="4"}} {polyline {@ points="{curve {A.new {P1} {P01} {P0}} 20}" stroke="#0f0" fill="transparent" stroke-width="4"}} {polyline {@ points="{curve {A.new {P2} {P12} {P1}} 20}" stroke="#00f" fill="transparent" stroke-width="4"}} {dot {P0} 10 #fff} {dot {P1} 10 #fff} {dot {P2} 10 #fff} {dot {P02} 5 #ff0} {dot {P20} 5 #f00} {dot {P10} 5 #ff0} {dot {P01} 5 #f00} {dot {P21} 5 #ff0} {dot {P12} 5 #f00} }} _p {i This page is written, enriched and structured, all algorithms are computed and drawn (in about 8ms) using exclusively the [[lambdatalk|?view=start]] language. Click the right part of the pages's title, {b lambdaway :: {u bezier_3}} to analyze the code and freely edit it.} _p {i alain marty 2022/06/05} _p [[HN|https://news.ycombinator.com/item?id=31628899]] _h2 refs _ul [[rosettacode.org|http://rosettacode.org/wiki/Curve_that_touches_three_points]] _ul [[casteljau]], for some alternatives to the Bézier algorithm. _ul ...
lambdaway v.20211111