Bitmap/Bézier curves/Cubic: Difference between revisions

no edit summary
mNo edit summary
imported>Chinhouse
No edit summary
 
(47 intermediate revisions by 23 users not shown)
Line 1:
[[Category:Geometry]]
{{task|Raster graphics operations}}
 
Using the data storage type defined [[Basic_bitmap_storage|on this page]] for raster images, and the <tt>draw_line</tt> function defined in [[Bresenham's_line_algorithm|this other one]], draw a '''cubic bezier curve'''
([[wp:Bezier_curves#Cubic_B.C3.A9zier_curves|definition on Wikipedia]]).
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">T Colour
Byte r, g, b
 
F ==(other)
R .r == other.r & .g == other.g & .b == other.b
 
F (r, g, b)
.r = r
.g = g
.b = b
 
V black = Colour(0, 0, 0)
V white = Colour(255, 255, 255)
 
T Bitmap
Int width, height
Colour background
[[Colour]] map
 
F (width = 40, height = 40, background = white)
assert(width > 0 & height > 0)
.width = width
.height = height
.background = background
.map = (0 .< height).map(h -> (0 .< @width).map(w -> @@background))
 
F fillrect(x, y, width, height, colour = black)
assert(x >= 0 & y >= 0 & width > 0 & height > 0)
L(h) 0 .< height
L(w) 0 .< width
.map[y + h][x + w] = colour
 
F chardisplay()
V txt = .map.map(row -> row.map(bit -> (I bit == @@.background {‘ ’} E ‘@’)).join(‘’))
txt = txt.map(row -> ‘|’row‘|’)
txt.insert(0, ‘+’(‘-’ * .width)‘+’)
txt.append(‘+’(‘-’ * .width)‘+’)
print(reversed(txt).join("\n"))
 
F set(x, y, colour = black)
.map[y][x] = colour
 
F get(x, y)
R .map[y][x]
 
F line(x0, y0, x1, y1)
‘Bresenham's line algorithm’
V dx = abs(x1 - x0)
V dy = abs(y1 - y0)
V (x, y) = (x0, y0)
V sx = I x0 > x1 {-1} E 1
V sy = I y0 > y1 {-1} E 1
I dx > dy
V err = dx / 2.0
L x != x1
.set(x, y)
err -= dy
I err < 0
y += sy
err += dx
x += sx
E
V err = dy / 2.0
L y != y1
.set(x, y)
err -= dx
I err < 0
x += sx
err += dy
y += sy
.set(x, y)
 
F cubicbezier(x0, y0, x1, y1, x2, y2, x3, y3, n = 20)
[(Int, Int)] pts
L(i) 0 .. n
V t = Float(i) / n
V a = (1. - t) ^ 3
V b = 3. * t * (1. - t) ^ 2
V c = 3.0 * t ^ 2 * (1.0 - t)
V d = t ^ 3
 
V x = Int(a * x0 + b * x1 + c * x2 + d * x3)
V y = Int(a * y0 + b * y1 + c * y2 + d * y3)
pts.append((x, y))
L(i) 0 .< n
.line(pts[i][0], pts[i][1], pts[i + 1][0], pts[i + 1][1])
 
V bitmap = Bitmap(17, 17)
bitmap.cubicbezier(16, 1, 1, 4, 3, 16, 15, 11)
bitmap.chardisplay()</syntaxhighlight>
 
{{out}}
<pre>
+-----------------+
| |
| |
| |
| |
| @@@@ |
| @@@ @@@ |
| @ |
| @ |
| @ |
| @ |
| @ |
| @ |
| @ |
| @ |
| @@@@ |
| @@@@|
| |
+-----------------+
</pre>
=={{header|Action!}}==
{{libheader|Action! Bitmap tools}}
{{libheader|Action! Tool Kit}}
{{libheader|Action! Real Math}}
<syntaxhighlight lang="action!">INCLUDE "H6:RGBLINE.ACT" ;from task Bresenham's line algorithm
INCLUDE "H6:REALMATH.ACT"
 
RGB black,yellow,violet,blue
 
TYPE IntPoint=[INT x,y]
 
PROC CubicBezier(RgbImage POINTER img
IntPoint POINTER p1,p2,p3,p4 RGB POINTER col)
INT i,n=[20],prevX,prevY,nextX,nextY
REAL one,two,three,ri,rn,rt,ra,rb,rc,rd,tmp1,tmp2,tmp3
REAL x1,y1,x2,y2,x3,y3,x4,y4
 
IntToReal(p1.x,x1) IntToReal(p1.y,y1)
IntToReal(p2.x,x2) IntToReal(p2.y,y2)
IntToReal(p3.x,x3) IntToReal(p3.y,y3)
IntToReal(p4.x,x4) IntToReal(p4.y,y4)
IntToReal(1,one) IntToReal(2,two)
IntToReal(3,three) IntToReal(n,rn)
FOR i=0 TO n
DO
prevX=nextX prevY=nextY
 
IntToReal(i,ri)
RealDiv(ri,rn,rt) ;t=i/n
RealSub(one,rt,tmp1) ;tmp1=1-t
RealMult(tmp1,tmp1,tmp2) ;tmp2=(1-t)^2
RealMult(tmp2,tmp1,ra) ;a=(1-t)^3
RealMult(three,rt,tmp2) ;tmp2=3*t
RealMult(tmp1,tmp1,tmp3) ;tmp3=(1-t)^2
RealMult(tmp2,tmp3,rb) ;b=3*t*(1-t)^2
 
RealMult(three,rt,tmp2) ;tmp2=3*t
RealMult(rt,tmp1,tmp3) ;tmp3=t*(1-t)
RealMult(tmp2,tmp3,rc) ;c=3*t^2*(1-t)
 
RealMult(rt,rt,tmp2) ;tmp2=t^2
RealMult(tmp2,rt,rd) ;d=t^3
 
RealMult(ra,x1,tmp1) ;tmp1=a*x1
RealMult(rb,x2,tmp2) ;tmp2=b*x2
RealAdd(tmp1,tmp2,tmp3) ;tmp3=a*x1+b*x2
RealMult(rc,x3,tmp1) ;tmp1=c*x3
RealAdd(tmp3,tmp1,tmp2) ;tmp2=a*x1+b*x2+c*x3
RealMult(rd,x4,tmp1) ;tmp1=d*x4
RealAdd(tmp2,tmp1,tmp3) ;tmp3=a*x1+b*x2+c*x3+d*x4
nextX=Round(tmp3)
 
RealMult(ra,y1,tmp1) ;tmp1=a*y1
RealMult(rb,y2,tmp2) ;tmp2=b*y2
RealAdd(tmp1,tmp2,tmp3) ;tmp3=a*y1+b*y2
RealMult(rc,y3,tmp1) ;tmp1=c*y3
RealAdd(tmp3,tmp1,tmp2) ;tmp2=a*y1+b*y2+c*y3
RealMult(rd,y4,tmp1) ;tmp1=d*y4
RealAdd(tmp2,tmp1,tmp3) ;tmp3=a*y1+b*y2+c*y3+d*y4
nextY=Round(tmp3)
 
IF i>0 THEN
RgbLine(img,prevX,prevY,nextX,nextY,col)
FI
OD
RETURN
 
PROC DrawImage(RgbImage POINTER img BYTE x,y)
RGB POINTER ptr
BYTE i,j
 
ptr=img.data
FOR j=0 TO img.h-1
DO
FOR i=0 TO img.w-1
DO
IF RgbEqual(ptr,yellow) THEN
Color=1
ELSEIF RgbEqual(ptr,violet) THEN
Color=2
ELSEIF RgbEqual(ptr,blue) THEN
Color=3
ELSE
Color=0
FI
Plot(x+i,y+j)
ptr==+RGBSIZE
OD
OD
RETURN
 
PROC Main()
RgbImage img
BYTE CH=$02FC,width=[70],height=[40]
BYTE ARRAY ptr(8400)
IntPoint p1,p2,p3,p4
 
Graphics(7+16)
SetColor(0,13,12) ;yellow
SetColor(1,4,8) ;violet
SetColor(2,8,6) ;blue
SetColor(4,0,0) ;black
 
RgbBlack(black)
RgbYellow(yellow)
RgbViolet(violet)
RgbBlue(blue)
 
InitRgbImage(img,width,height,ptr)
FillRgbImage(img,black)
 
p1.x=0 p1.y=3
p2.x=10 p2.y=39
p3.x=69 p3.y=31
p4.x=40 p4.y=8
RgbLine(img,p1.x,p1.y,p2.x,p2.y,blue)
RgbLine(img,p2.x,p2.y,p3.x,p3.y,blue)
RgbLine(img,p3.x,p3.y,p4.x,p4.y,blue)
CubicBezier(img,p1,p2,p3,p4,yellow)
SetRgbPixel(img,p1.x,p1.y,violet)
SetRgbPixel(img,p2.x,p2.y,violet)
SetRgbPixel(img,p3.x,p3.y,violet)
SetRgbPixel(img,p4.x,p4.y,violet)
 
DrawImage(img,(160-width)/2,(96-height)/2)
 
DO UNTIL CH#$FF OD
CH=$FF
RETURN</syntaxhighlight>
{{out}}
[https://gitlab.com/amarok8bit/action-rosetta-code/-/raw/master/images/B%C3%A9zier_curves_cubic.png Screenshot from Atari 8-bit computer]
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">procedure Cubic_Bezier
( Picture : in out Image;
P1, P2, P3, P4 : Point;
Line 29 ⟶ 277:
Line (Picture, Points (I), Points (I + 1), Color);
end loop;
end Cubic_Bezier;</langsyntaxhighlight>
The following test
<langsyntaxhighlight lang="ada"> X : Image (1..16, 1..16);
begin
Fill (X, White);
Cubic_Bezier (X, (16, 1), (1, 4), (3, 16), (15, 11), Black);
Print (X);</langsyntaxhighlight>
should produce output:
<pre>
Line 60 ⟶ 308:
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.6 algol68g-2.6].}}
{{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of '''format'''[ted] ''transput''.}}
'''File: prelude/Bitmap/Bezier_curves/Cubic.a68'''<langsyntaxhighlight lang="algol68"># -*- coding: utf-8 -*- #
 
cubic bezier OF class image :=
Line 85 ⟶ 333:
END # cubic bezier #;
 
SKIP</langsyntaxhighlight>'''File: test/Bitmap/Bezier_curves/Cubic.a68'''<langsyntaxhighlight lang="algol68">#!/usr/bin/a68g --script #
# -*- coding: utf-8 -*- #
Line 98 ⟶ 346:
(cubic bezier OF class image)(x, (16, 1), (1, 4), (3, 16), (15, 11), (black OF class image), EMPTY);
(print OF class image) (x)
)</langsyntaxhighlight>'''Output:'''
<pre>
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Line 117 ⟶ 365:
000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
</pre>
=={{header|ATS}}==
See [[Bresenham_tasks_in_ATS]].
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
[[Image:beziercubic_bbc.gif|right]]
<langsyntaxhighlight lang="bbcbasic"> Width% = 200
Height% = 200
Line 172 ⟶ 422:
GCOL 1
LINE x%*2,y%*2,x%*2,y%*2
ENDPROC</langsyntaxhighlight>
 
=={{header|C}}==
"Interface" <tt>imglib.h</tt>.
 
<langsyntaxhighlight lang="c">void cubic_bezier(
image img,
unsigned int x1, unsigned int y1,
Line 185 ⟶ 435:
color_component r,
color_component g,
color_component b );</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">#include <math.h>
 
/* number of segments for the curve */
Line 240 ⟶ 490:
}
#undef plot
#undef line</langsyntaxhighlight>
 
=={{header|D}}==
This solution uses two modules, from the Grayscale image and Bresenham's line algorithm Tasks.
<langsyntaxhighlight lang="d">import grayscale_image, bitmap_bresenhams_line_algorithm;
 
struct Pt { int x, y; } // Signed.
Line 252 ⟶ 501:
in Pt p1, in Pt p2, in Pt p3, in Pt p4,
in Color color)
pure nothrow @nogc if (nSegments > 0) {
Pt[nSegments + 1] points = void;
 
foreach (immutable i, ref p; points) {
immutable double t = i / cast(double)(nSegments),
a = (1.0 - t) ^^ 3,
b = 3.0 * t * (1.0 - t) ^^ 2,
Line 277 ⟶ 526:
Gray.black);
im.textualShow();
}</langsyntaxhighlight>
{{out}}
<pre>.................
Line 296 ⟶ 545:
.................
.................</pre>
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
 
[[File:DelphiCubicBezier.png|frame|none]]
 
<syntaxhighlight lang="Delphi">
 
{This code would normally be stored in a separate library, but they presented here for clarity}
 
type T2DVector=packed record
X,Y: double;
end;
 
type T2DLine = packed record
P1,P2: T2DVector;
end;
 
type T2DVectorArray = array of T2DVector;
 
 
function MakeVector2D(const X,Y: double): T2DVector;
{Create 2D Vector from X and Y}
begin
Result.X:=X;
Result.Y:=Y;
end;
 
 
 
 
procedure DoCubicSplineLine(Steps: Integer; L1,L2: T2DLine; ClearArray: boolean; var PG: T2DVectorArray);
{Do cubic Bezier spline between L1.P1 and L2.P1 }
{L1.P1 = Point1, L1.P2 = Control1, L2.P1=Control2, L2.P2 = Point2}
var P: Integer;
var V: T2DVector;
var T: double;
var A,B,C,D,E,F,G,H : double;
begin
if ClearArray then SetLength(PG,0);
A := L2.P2.X - (3 * L2.P1.X) + (3 * L1.P2.X) - L1.P1.X;
B := (3 * L2.P1.X) - (6 * L1.P2.X) + (3 * L1.P1.X);
C := (3 * L1.P2.X) - (3 * L1.P1.X);
D := L1.P1.X;
 
E := L2.P2.Y - (3 * L2.P1.Y) + (3 * L1.P2.Y) - L1.P1.Y;
F := (3 * L2.P1.Y) - (6 * L1.P2.Y) + (3 * L1.P1.Y);
G := (3 * L1.P2.Y) - (3 * L1.P1.Y);
H := L1.P1.Y;
 
for P:=0 to Steps-1 do
begin
T :=P / (Steps-1);
V.X := (((A * T) + B) * T + C) * T + D;
V.Y := (((E * T) + F) * T + G) * T + H;
SetLength(PG,Length(PG)+1);
PG[High(PG)]:=V;
end;
end;
 
procedure MarkPoint(Image: TImage; P: TPoint);
begin
Image.Canvas.Pen.Width:=2;
Image.Canvas.Pen.Color:=clRed;
Image.Canvas.MoveTo(Trunc(P.X-3),Trunc(P.Y-3));
Image.Canvas.LineTo(Trunc(P.X+3),Trunc(P.Y+3));
Image.Canvas.MoveTo(Trunc(P.X+3),Trunc(P.Y-3));
Image.Canvas.LineTo(Trunc(P.X-3),Trunc(P.Y+3));
end;
 
 
 
procedure DrawControlPoint(Image: TImage; L: T2DLine);
var P1,P2: TPoint;
begin
Image.Canvas.Pen.Width:=1;
Image.Canvas.Pen.Color:=clBlue;
P1:=Point(Trunc(L.P1.X),Trunc(L.P1.Y));
P2:=Point(Trunc(L.P2.X),Trunc(L.P2.Y));
 
Image.Canvas.MoveTo(P1.X,P1.Y);
Image.Canvas.LineTo(P2.X,P2.Y);
Image.Canvas.Pen.Color:=clRed;
MarkPoint(Image,P2);
end;
 
 
 
procedure DrawOneSpline(Image: TImage; L1,L2: T2DLine);
var PG: T2DVectorArray;
var I: integer;
begin
DoCubicSplineLine(20,L1,L2,True,PG);
DrawControlPoint(Image,L1);
DrawControlPoint(Image,L2);
 
Image.Canvas.Pen.Width:=2;
Image.Canvas.Pen.Color:=clRed;
Image.Canvas.MoveTo(Trunc(PG[0].X),Trunc(PG[0].Y));
for I:=1 to High(PG) do
Image.Canvas.LineTo(Trunc(PG[I].X),Trunc(PG[I].Y));
end;
 
procedure ShowBezierCurve(Image: TImage);
var L1,L2: T2DLine;
begin
L1.P1:=MakeVector2D(50,50);
L1.P2:=MakeVector2D(250,50);
L2.P1:=MakeVector2D(50,250);
L2.P2:=MakeVector2D(250,250);
DrawOneSpline(Image, L1,L2);
L1.P1:=MakeVector2D(250,250);
L1.P2:=MakeVector2D(450,250);
L2.P1:=MakeVector2D(250,50);
L2.P2:=MakeVector2D(450,50);
DrawOneSpline(Image, L1,L2);
 
 
Image.Invalidate;
end;
</syntaxhighlight>
{{out}}
<pre>
 
Elapsed Time: 1.171 ms.
</pre>
 
=={{header|F Sharp|F#}}==
<syntaxhighlight lang="f#">
<lang f#>
/// Uses Vector<float> from Microsoft.FSharp.Math (in F# PowerPack)
module CubicBezier
Line 316 ⟶ 692:
vector [x; y])
 
</syntaxhighlight>
</lang>
<syntaxhighlight lang="f#">
<lang f#>
// For rendering..
let drawPoints points (canvas:System.Windows.Controls.Canvas) =
Line 331 ⟶ 707:
 
points |> List.fold renderPoint points.Head
</syntaxhighlight>
</lang>
=={{header|Factor}}==
The points should probably be in a sequence...
<syntaxhighlight lang="factor">USING: arrays kernel locals math math.functions
rosettacode.raster.storage sequences ;
IN: rosettacode.raster.line
 
! this gives a function
:: (cubic-bezier) ( P0 P1 P2 P3 -- bezier )
[ :> x
1 x - 3 ^ P0 n*v
1 x - sq 3 * x * P1 n*v
1 x - 3 * x sq * P2 n*v
x 3 ^ P3 n*v
v+ v+ v+ ] ; inline
! gives an interval of x from 0 to 1 to map the bezier function
: t-interval ( x -- interval )
[ iota ] keep 1 - [ / ] curry map ;
! turns a list of points into the list of lines between them
: points-to-lines ( seq -- seq )
dup rest [ 2array ] 2map ;
: draw-lines ( {R,G,B} points image -- )
[ [ first2 ] dip draw-line ] curry with each ;
:: bezier-lines ( {R,G,B} P0 P1 P2 P3 image -- )
! 100 is an arbitrary value.. could be given as a parameter..
100 t-interval P0 P1 P2 P3 (cubic-bezier) map
points-to-lines
{R,G,B} swap image draw-lines ;</syntaxhighlight>
=={{header|FBSL}}==
Windows' graphics origin is located at the bottom-left corner of device bitmap.
 
'''Translation of BBC BASIC using pure FBSL's built-in graphics functions:'''
<langsyntaxhighlight lang="qbasic">#DEFINE WM_LBUTTONDOWN 513
#DEFINE WM_CLOSE 16
 
Line 393 ⟶ 795:
WEND
END SUB
END SUB</langsyntaxhighlight>
'''Output:''' [[File:FBSLBezierCube.PNG]]
 
=={{header|Factor}}==
The points should probably be in a sequence...
<lang factor>USING: arrays kernel locals math math.functions
rosettacode.raster.storage sequences ;
IN: rosettacode.raster.line
 
! this gives a function
:: (cubic-bezier) ( P0 P1 P2 P3 -- bezier )
[ :> x
1 x - 3 ^ P0 n*v
1 x - sq 3 * x * P1 n*v
1 x - 3 * x sq * P2 n*v
x 3 ^ P3 n*v
v+ v+ v+ ] ; inline
! gives an interval of x from 0 to 1 to map the bezier function
: t-interval ( x -- interval )
[ iota ] keep 1 - [ / ] curry map ;
! turns a list of points into the list of lines between them
: points-to-lines ( seq -- seq )
dup rest [ 2array ] 2map ;
: draw-lines ( {R,G,B} points image -- )
[ [ first2 ] dip draw-line ] curry with each ;
:: bezier-lines ( {R,G,B} P0 P1 P2 P3 image -- )
! 100 is an arbitrary value.. could be given as a parameter..
100 t-interval P0 P1 P2 P3 (cubic-bezier) map
points-to-lines
{R,G,B} swap image draw-lines ;</lang>
 
=={{header|Fortran}}==
{{trans|C}}
Line 429 ⟶ 802:
This subroutine should go inside the <code>RCImagePrimitive</code> module (see [[Bresenham's line algorithm]])
 
<langsyntaxhighlight lang="fortran">subroutine cubic_bezier(img, p1, p2, p3, p4, color)
type(rgbimage), intent(inout) :: img
type(point), intent(in) :: p1, p2, p3, p4
Line 440 ⟶ 813:
t = real(i) / real(N_SEG)
a = (1.0 - t)**3.0
b = 3.0 * t * (1.0 - t)**2.0
c = 3.0 * (1.0 - t) * t**2.0
d = t**3.0
x = a * p1%x + b * p2%x + c * p3%x + d * p4%x
Line 455 ⟶ 828:
end do
 
end subroutine cubic_bezier</langsyntaxhighlight>
=={{header|FreeBASIC}}==
{{trans|BBC BASIC}}
<syntaxhighlight lang="freebasic">' version 01-11-2016
' compile with: fbc -s console
 
' translation from Bitmap/Bresenham's line algorithm C entry
Sub Br_line(x0 As Integer, y0 As Integer, x1 As Integer, y1 As Integer, _
Col As UInteger = &HFFFFFF)
 
Dim As Integer dx = Abs(x1 - x0), dy = Abs(y1 - y0)
Dim As Integer sx = IIf(x0 < x1, 1, -1)
Dim As Integer sy = IIf(y0 < y1, 1, -1)
Dim As Integer er = IIf(dx > dy, dx, -dy) \ 2, e2
 
Do
PSet(x0, y0), col
If (x0 = x1) And (y0 = y1) Then Exit Do
e2 = er
If e2 > -dx Then Er -= dy : x0 += sx
If e2 < dy Then Er += dx : y0 += sy
Loop
 
End Sub
 
' Bitmap/Bézier curves/Cubic BBC BASIC entry
Sub beziercubic(x1 As Double, y1 As Double, x2 As Double, y2 As Double, _
x3 As Double, y3 As Double, x4 As Double, y4 As Double, _
n As ULong, col As UInteger = &HFFFFFF)
 
Type point_
x As Integer
y As Integer
End Type
 
Dim As ULong i
Dim As Double t, t1, a, b, c, d
Dim As point_ p(n)
 
For i = 0 To n
t = i / n
t1 = 1 - t
a = t1 ^ 3
b = t * t1 * t1 * 3
c = t * t * t1 * 3
d = t ^ 3
p(i).x = Int(a * x1 + b * x2 + c * x3 + d * x4 + .5)
p(i).y = Int(a * y1 + b * y2 + c * y3 + d * y4 + .5)
Next
 
For i = 0 To n -1
Br_line(p(i).x, p(i).y, p(i +1).x, p(i +1).y, col)
Next
 
End Sub
 
' ------=< MAIN >=------
 
ScreenRes 250,250,32 ' 0,0 in top left corner
 
beziercubic(160, 150, 10, 120, 30, 0, 150, 50, 20)
 
 
' empty keyboard buffer
While Inkey <> "" : Wend
Print : Print "hit any key to end program"
Sleep
End</syntaxhighlight>
=={{header|Go}}==
{{trans|C}}
<langsyntaxhighlight lang="go">package raster
 
const b3Seg = 30
Line 487 ⟶ 926:
func (b *Bitmap) Bézier3Rgb(x1, y1, x2, y2, x3, y3, x4, y4 int, c Rgb) {
b.Bézier3(x1, y1, x2, y2, x3, y3, x4, y4, c.Pixel())
}</langsyntaxhighlight>
Demonstration program:
[[File:GoBez3.png|thumb|right]]
<langsyntaxhighlight lang="go">package main
 
import (
Line 504 ⟶ 943:
fmt.Println(err)
}
}</langsyntaxhighlight>
 
=={{header|J}}==
'''Solution:'''<br>
See the [[J:Essays/Bernstein Polynomials|Bernstein Polynomials essay]] on the [[J:|J Wiki]].<br>
Uses code from [[Basic_bitmap_storage#J|Basic bitmap storage]], [[Bresenham's_line_algorithm#J|Bresenham's line algorithm]] and [[Midpoint_circle_algorithm#J|Midpoint circle algorithm]].
<langsyntaxhighlight lang="j">require 'numeric'
 
bik=: 2 : '((*&(u!v))@(^&u * ^&(v-u)@-.))'
Line 530 ⟶ 968:
NB. eg: (42 40 10 30 186 269 26 187;255 0 0) drawBezier myimg
NB. x is: 2-item list of boxed (controlpoints) ; (color)
drawBezier=: (1&{:: ;~ 2 ]\ [: roundint@getBezierPoints"1 (0&{::))@[ drawLines ]</langsyntaxhighlight>
 
'''Example usage:'''
<langsyntaxhighlight lang="j">myimg=: 0 0 255 makeRGB 300 300
]randomctrlpts=: ,3 2 ?@$ }:$ myimg NB. 3 control points - quadratic
]randomctrlpts=: ,4 2 ?@$ }:$ myimg NB. 4 control points - cubic
myimg=: ((2 ,.~ _2]\randomctrlpts);255 0 255) drawCircles myimg NB. draw control points
viewRGB (randomctrlpts; 255 255 0) drawBezier myimg NB. display image with bezier line</langsyntaxhighlight>
 
=={{header|MathematicaJava}}==
Using the BasicBitmapStorage class from the [[Bitmap]] task to produce a runnable program.
<lang Mathematica>points= {{0, 0}, {1, 1}, {2, -1}, {3, 0}};
<syntaxhighlight lang ="java">
Graphics[{BSplineCurve[points], Green, Line[points], Red, Point[points]}]</lang>
[[File:MmaCubicBezier.png]]
 
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
 
import javax.imageio.ImageIO;
 
public final class BezierCubic {
 
public static void main(String[] args) throws IOException {
final int width = 200;
final int height = 200;
BasicBitmapStorage bitmap = new BasicBitmapStorage(width, height);
bitmap.fill(Color.YELLOW);
Point point1 = new Point(0, 150);
Point point2 = new Point(30, 50);
Point point3 = new Point(120, 130);
Point point4 = new Point(160, 30);
bitmap.cubicBezier(point1, point2, point3, point4, Color.BLACK, 20);
File bezierFile = new File("CubicBezierJava.jpg");
ImageIO.write((RenderedImage) bitmap.getImage(), "jpg", bezierFile);
}
}
final class BasicBitmapStorage {
 
public BasicBitmapStorage(int width, int height) {
image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
}
public void fill(Color color) {
Graphics graphics = image.getGraphics();
graphics.setColor(color);
graphics.fillRect(0, 0, image.getWidth(), image.getHeight());
}
 
public Color getPixel(int x, int y) {
return new Color(image.getRGB(x, y));
}
public void setPixel(int x, int y, Color color) {
image.setRGB(x, y, color.getRGB());
}
public Image getImage() {
return image;
}
public void cubicBezier(
Point point1, Point point2, Point point3, Point point4, Color color, int intermediatePointCount) {
List<Point> points = new ArrayList<Point>();
for ( int i = 0; i <= intermediatePointCount; i++ ) {
final double t = (double) i / intermediatePointCount;
final double u = 1.0 - t;
final double a = u * u * u;
final double b = 3.0 * t * u * u;
final double c = 3.0 * t * t * u;
final double d = t * t * t;
final int x = (int) ( a * point1.x + b * point2.x + c * point3.x + d * point4.x );
final int y = (int) ( a * point1.y + b * point2.y + c * point3.y + d * point4.y );
points.add( new Point(x, y) );
setPixel(x, y, color);
}
for ( int i = 0; i < intermediatePointCount; i++ ) {
drawLine(points.get(i).x, points.get(i).y, points.get(i + 1).x, points.get(i + 1).y, color);
}
}
public void drawLine(int x0, int y0, int x1, int y1, Color color) {
final int dx = Math.abs(x1 - x0);
final int dy = Math.abs(y1 - y0);
final int xIncrement = x0 < x1 ? 1 : -1;
final int yIncrement = y0 < y1 ? 1 : -1;
int error = ( dx > dy ? dx : -dy ) / 2;
while ( x0 != x1 || y0 != y1 ) {
setPixel(x0, y0, color);
int error2 = error;
if ( error2 > -dx ) {
error -= dy;
x0 += xIncrement;
}
if ( error2 < dy ) {
error += dx;
y0 += yIncrement;
}
}
setPixel(x0, y0, color);
}
private BufferedImage image;
}
</syntaxhighlight>
{{ out }}
[[Media:CubicBezierJava.jpg]]
 
=={{header|JavaScript}}==
<syntaxhighlight lang="javascript">
function draw() {
var canvas = document.getElementById("container");
context = canvas.getContext("2d");
 
bezier3(20, 200, 700, 50, -300, 50, 380, 150);
// bezier3(160, 10, 10, 40, 30, 160, 150, 110);
// bezier3(0,149, 30,50, 120,130, 160,30, 0);
}
 
// http://rosettacode.org/wiki/Cubic_bezier_curves#C
function bezier3(x1, y1, x2, y2, x3, y3, x4, y4) {
var px = [], py = [];
for (var i = 0; i <= b3Seg; i++) {
var d = i / b3Seg;
var a = 1 - d;
var b = a * a;
var c = d * d;
a = a * b;
b = 3 * b * d;
c = 3 * a * c;
d = c * d;
px[i] = parseInt(a * x1 + b * x2 + c * x3 + d * x4);
py[i] = parseInt(a * y1 + b * y2 + c * y3 + d * y4);
}
var x0 = px[0];
var y0 = py[0];
for (i = 1; i <= b3Seg; i++) {
var x = px[i];
var y = py[i];
drawPolygon(context, [[x0, y0], [x, y]], "red", "red");
x0 = x;
y0 = y;
}
}
function drawPolygon(context, polygon, strokeStyle, fillStyle) {
context.strokeStyle = strokeStyle;
context.beginPath();
 
context.moveTo(polygon[0][0],polygon[0][1]);
for (i = 1; i < polygon.length; i++)
context.lineTo(polygon[i][0],polygon[i][1]);
 
context.closePath();
context.stroke();
 
if (fillStyle == undefined)
return;
context.fillStyle = fillStyle;
context.fill();
}
</syntaxhighlight>
=={{header|Julia}}==
{{works with|Julia|0.6}}
 
<syntaxhighlight lang="julia">using Images
 
function cubicbezier!(xy::Matrix,
img::Matrix = fill(RGB(255.0, 255.0, 255.0), 17, 17),
col::ColorTypes.Color = convert(eltype(img), Gray(0.0)),
n::Int = 20)
t = collect(0:n) ./ n
M = hcat((1 .- t) .^ 3, # a
3t .* (1 .- t) .^ 2, # b
3t .^ 2 .* (1 .- t), # c
t .^ 3) # d
p = floor.(Int, M * xy)
for i in 1:n
drawline!(img, p[i, :]..., p[i+1, :]..., col)
end
return img
end
 
xy = [16 1; 1 4; 3 16; 15 11]
cubicbezier!(xy)</syntaxhighlight>
=={{header|Kotlin}}==
This incorporates code from other relevant tasks in order to provide a runnable example.
<syntaxhighlight lang="scala">// Version 1.2.40
 
import java.awt.Color
import java.awt.Graphics
import java.awt.image.BufferedImage
import kotlin.math.abs
import java.io.File
import javax.imageio.ImageIO
 
class Point(var x: Int, var y: Int)
 
class BasicBitmapStorage(width: Int, height: Int) {
val image = BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR)
 
fun fill(c: Color) {
val g = image.graphics
g.color = c
g.fillRect(0, 0, image.width, image.height)
}
 
fun setPixel(x: Int, y: Int, c: Color) = image.setRGB(x, y, c.getRGB())
 
fun getPixel(x: Int, y: Int) = Color(image.getRGB(x, y))
 
fun drawLine(x0: Int, y0: Int, x1: Int, y1: Int, c: Color) {
val dx = abs(x1 - x0)
val dy = abs(y1 - y0)
val sx = if (x0 < x1) 1 else -1
val sy = if (y0 < y1) 1 else -1
var xx = x0
var yy = y0
var e1 = (if (dx > dy) dx else -dy) / 2
var e2: Int
while (true) {
setPixel(xx, yy, c)
if (xx == x1 && yy == y1) break
e2 = e1
if (e2 > -dx) { e1 -= dy; xx += sx }
if (e2 < dy) { e1 += dx; yy += sy }
}
}
 
fun cubicBezier(p1: Point, p2: Point, p3: Point, p4: Point, clr: Color, n: Int) {
val pts = List(n + 1) { Point(0, 0) }
for (i in 0..n) {
val t = i.toDouble() / n
val u = 1.0 - t
val a = u * u * u
val b = 3.0 * t * u * u
val c = 3.0 * t * t * u
val d = t * t * t
pts[i].x = (a * p1.x + b * p2.x + c * p3.x + d * p4.x).toInt()
pts[i].y = (a * p1.y + b * p2.y + c * p3.y + d * p4.y).toInt()
setPixel(pts[i].x, pts[i].y, clr)
}
for (i in 0 until n) {
val j = i + 1
drawLine(pts[i].x, pts[i].y, pts[j].x, pts[j].y, clr)
}
}
}
 
fun main(args: Array<String>) {
val width = 200
val height = 200
val bbs = BasicBitmapStorage(width, height)
with (bbs) {
fill(Color.cyan)
val p1 = Point(0, 149)
val p2 = Point(30, 50)
val p3 = Point(120, 130)
val p4 = Point(160, 30)
cubicBezier(p1, p2, p3, p4, Color.black, 20)
val cbFile = File("cubic_bezier.jpg")
ImageIO.write(image, "jpg", cbFile)
}
}</syntaxhighlight>
=={{header|Lambdatalk}}==
<syntaxhighlight lang="scheme">
Drawing a cubic bezier curve out of any SVG or CANVAS frame.
1) interpolating 4 points
 
The Bézier curve is defined as an array of 4 given points,
each defined as an array of 2 numbers.
The bezier function returns the point interpolating the 4 points.
 
{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}}} }}
-> bezier
 
2) plotting a dot
 
We don't draw in any SVG or CANVAS frame, but directly in the HTML page,
using div HTML blocks designed as colored circles.
 
{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;"}}}}
-> dot
 
3) defining 4 control points
 
{def Q0 {A.new 150 150}} -> Q0
{def Q1 {A.new 500 300}} -> Q1
{def Q2 {A.new 100 500}} -> Q2
{def Q3 {A.new 300 500}} -> Q3
 
4) defining 2 curves
 
We use the same control points but in different orders to define two curves
 
{def BZ1 {A.new {Q0} {Q1} {Q2} {Q3}}}
-> BZ1
{def BZ2 {A.new {Q0} {Q2} {Q1} {Q3}}}
-> BZ2
 
5) drawing curves and dots
 
We map the bezier function on a serie of values in a range [start end step]
 
{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}
 
The result can be seen in http://lambdaway.free.fr/lambdawalks/?view=bezier
 
</syntaxhighlight>
=={{header|Lua}}==
Starting with the code from [[Bitmap/Bresenham's line algorithm#Lua|Bitmap/Bresenham's line algorithm]], then extending:
<syntaxhighlight lang="lua">Bitmap.cubicbezier = function(self, x1, y1, x2, y2, x3, y3, x4, y4, nseg)
nseg = nseg or 10
local prevx, prevy, currx, curry
for i = 0, nseg do
local t = i / nseg
local a, b, c, d = (1-t)^3, 3*t*(1-t)^2, 3*t^2*(1-t), t^3
prevx, prevy = currx, curry
currx = math.floor(a * x1 + b * x2 + c * x3 + d * x4 + 0.5)
curry = math.floor(a * y1 + b * y2 + c * y3 + d * y4 + 0.5)
if i > 0 then
self:line(prevx, prevy, currx, curry)
end
end
end
local bitmap = Bitmap(61,21)
bitmap:clear()
bitmap:cubicbezier( 1,1, 15,41, 45,-20, 59,19 )
bitmap:render({[0x000000]='.', [0xFFFFFFFF]='X'})</syntaxhighlight>
{{out}}
<pre>.............................................................
.X...........................................................
.X...........................................................
..X..........................................................
...X.........................................................
...X.....................................XXXXX...............
....X.................................XXX.....XXXX...........
....X..............................XXX............X..........
.....X...........................XX................X.........
.....X.........................XX...................X........
......X.....................XXX......................XX......
.......X..................XX..........................X......
........X...............XX.............................X.....
.........X...........XXX................................X....
..........XXXX....XXX...................................X....
..............XXXX.......................................X...
.........................................................X...
..........................................................X..
..........................................................X..
...........................................................X.
.............................................................</pre>
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">points= {{0, 0}, {1, 1}, {2, -1}, {3, 0}};
Graphics[{BSplineCurve[points], Green, Line[points], Red, Point[points]}]</syntaxhighlight>
[[File:MmaCubicBezier.png]]
=={{header|MATLAB}}==
Note: Store this function in a file named "bezierCubic.mat" in the @Bitmap folder for the Bitmap class defined [[Bitmap#MATLAB|here]].
<syntaxhighlight lang="matlab">
<lang MATLAB>
function bezierCubic(obj,pixel_0,pixel_1,pixel_2,pixel_3,color,varargin)
 
Line 577 ⟶ 1,406:
end
</syntaxhighlight>
</lang>
 
Sample usage:
This will generate the image example for the PHP solution.
<syntaxhighlight lang="matlab">
<lang MATLAB>
>> img = Bitmap(200,200);
>> img.fill([255 255 255]);
>> img.bezierCubic([160 10],[10 40],[30 160],[150 110],[255 0 0],110);
>> disp(img)
</syntaxhighlight>
</lang>
 
=={{header|MiniScript}}==
This GUI implementation is for use with [http://miniscript.org/MiniMicro Mini Micro].
<syntaxhighlight lang="miniscript">
Point = {"x": 0, "y":0}
Point.init = function(x, y)
p = new Point
p.x = x; p.y = y
return p
end function
 
drawLine = function(img, x0, y0, x1, y1, colr)
sign = function(a, b)
if a < b then return 1
return -1
end function
dx = abs(x1 - x0)
sx = sign(x0, x1)
dy = abs(y1 - y0)
sy = sign(y0, y1)
if dx > dy then
err = dx
else
err = -dy
end if
err = floor(err / 2)
while true
img.setPixel x0, y0, colr
if x0 == x1 and y0 == y1 then break
e2 = err
if e2 > -dx then
err -= dy
x0 += sx
end if
if e2 < dy then
err += dx
y0 += sy
end if
end while
end function
 
cubicBezier = function(img, p1, p2, p3, p4, numPoints, colr)
points = []
for i in range(0, numPoints)
t = i / numPoints
u = 1 - t
a = (1 - t)^3
b = 3 * t * (1 - t)^2
c = 3 * t^2 * (1 - t)
d = t^3
x = floor(a * p1.x + b * p2.x + c * p3.x + d * p4.x)
y = floor(a * p1.y + b * p2.y + c * p3.y + d * p4.y)
points.push(Point.init(x, y))
img.setPixel x, y, colr
end for
for i in range(1, numPoints)
drawLine img, points[i-1].x, points[i-1].y, points[i].x, points[i].y, colr
end for
end function
 
bezier = Image.create(480, 480)
p1 = Point.init(50, 100)
p2 = Point.init(200, 400)
p3 = Point.init(360, 0)
p4 = Point.init(300, 424)
 
cubicBezier bezier, p1, p2, p3, p4, 20, color.red
gfx.clear
gfx.drawImage bezier, 0, 0
</syntaxhighlight>
 
=={{header|Nim}}==
{{Trans|Ada}}
We use module “bitmap” for bitmap management and module “bresenham” to draw segments.
<syntaxhighlight lang="nim">import bitmap
import bresenham
import lenientops
 
proc drawCubicBezier*(
image: Image; pt1, pt2, pt3, pt4: Point; color: Color; nseg: Positive = 20) =
 
var points = newSeq[Point](nseg + 1)
 
for i in 0..nseg:
let t = i / nseg
let u = (1 - t) * (1 - t)
let a = (1 - t) * u
let b = 3 * t * u
let c = 3 * (t * t) * (1 - t)
let d = t * t * t
 
points[i] = (x: (a * pt1.x + b * pt2.x + c * pt3.x + d * pt4.x).toInt,
y: (a * pt1.y + b * pt2.y + c * pt3.y + d * pt4.y).toInt)
 
for i in 1..points.high:
image.drawLine(points[i - 1], points[i], color)
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
when isMainModule:
var img = newImage(16, 16)
img.fill(White)
img.drawCubicBezier((0, 15), (3, 0), (15, 2), (10, 14), Black)
img.print</syntaxhighlight>
 
{{out}}
<pre>................
................
................
................
.......HH.......
.....HH..HH.....
....H......H....
....H......H....
...H.......H....
..H........H....
.H.........H....
.H.........H....
.H.........H....
.H.........H....
H.........H.....
H...............</pre>
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">let cubic_bezier ~img ~color
~p1:(_x1, _y1)
~p2:(_x2, _y2)
Line 633 ⟶ 1,589:
in
by_pair pts (fun p0 p1 -> line ~p0 ~p1);
;;</langsyntaxhighlight>
=={{header|Phix}}==
Output similar to [[Bitmap/Bézier_curves/Cubic#Mathematica|Mathematica]]<br>
Requires new_image() from [[Bitmap#Phix|Bitmap]], bresLine() from [[Bitmap/Bresenham's_line_algorithm#Phix|Bresenham's_line_algorithm]], write_ppm() from [[Bitmap/Write_a_PPM_file#Phix|Write_a_PPM_file]]. <br>
Results may be verified with demo\rosetta\viewppm.exw
<syntaxhighlight lang="phix">-- demo\rosetta\Bitmap_BezierCubic.exw (runnable version)
include ppm.e -- black, green, red, white, new_image(), write_ppm(), bresLine() -- (covers above requirements)
 
function cubic_bezier(sequence img, atom x1, y1, x2, y2, x3, y3, x4, y4, integer colour, segments)
sequence pts = repeat(0,segments*2)
for i=0 to segments*2-1 by 2 do
atom t = i/segments,
t1 = 1-t,
a = power(t1,3),
b = 3*t*power(t1,2),
c = 3*power(t,2)*t1,
d = power(t,3)
pts[i+1] = floor(a*x1+b*x2+c*x3+d*x4)
pts[i+2] = floor(a*y1+b*y2+c*y3+d*y4)
end for
for i=1 to segments*2-2 by 2 do
img = bresLine(img, pts[i], pts[i+1], pts[i+2], pts[i+3], colour)
end for
return img
end function
 
sequence img = new_image(300,200,black)
img = cubic_bezier(img, 0,100, 100,0, 200,200, 300,100, white, 40)
img = bresLine(img,0,100,100,0,green)
img = bresLine(img,100,0,200,200,green)
img = bresLine(img,200,200,300,100,green)
img[1][100] = red
img[100][1] = red
img[200][200] = red
img[300][100] = red
write_ppm("Bezier.ppm",img)</syntaxhighlight>
=={{header|PHP}}==
[[Image:Cubic bezier curve PHP.png|right]]
Line 646 ⟶ 1,636:
Outputs image to the right directly to browser or stdout.
 
<langsyntaxhighlight lang="php"><?
 
$image = imagecreate(200, 200);
Line 675 ⟶ 1,665:
}
}
</syntaxhighlight>
</lang>
 
=={{header|PicoLisp}}==
This uses the 'brez' line drawing function from
[[Bitmap/Bresenham's line algorithm#PicoLisp]].
<langsyntaxhighlight PicoLisplang="picolisp">(scl 6)
 
(de cubicBezier (Img N X1 Y1 X2 Y2 X3 Y3 X4 Y4)
Line 703 ⟶ 1,692:
Y ) ) )
(inc 'X DX)
(inc 'Y DY) ) ) ) )</langsyntaxhighlight>
Test:
<langsyntaxhighlight PicoLisplang="picolisp">(let Img (make (do 200 (link (need 300 0)))) # Create image 300 x 200
(cubicBezier Img 24 20 120 540 33 -225 33 285 100)
(out "img.pbm" # Write to bitmap file
Line 712 ⟶ 1,701:
(mapc prinl Img) ) )
 
(call 'display "img.pbm")</langsyntaxhighlight>
=={{header|Processing}}==
<syntaxhighlight lang="prolog">noFill();
bezier(85, 20, 10, 10, 90, 90, 15, 80);
/*
bezier(x1, y1, x2, y2, x3, y3, x4, y4)
Can also be drawn in 3D.
bezier(x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4)
*/</syntaxhighlight>'''A working sketch with movable anchor and control points.
 
'''It can be run on line''' :<BR> [https://www.openprocessing.org/sketch/846556/ here.]
<syntaxhighlight lang="text">
float[] x = new float[4];
float[] y = new float[4];
boolean[] permitDrag = new boolean[4];
 
void setup() {
size(300, 300);
smooth();
// startpoint coordinates
x[0] = x[1] = 50;
y[0] = 50;
y[1] = y[2] = 150;
x[2] = x[3] = 250;
y[3] = 250;
}
 
void draw() {
background(255);
noFill();
stroke(0, 0, 255);
bezier(x[1], y[1], x[0], y[0], x[3], y[3], x[2], y[2]);
// the bezier handles
strokeWeight(1);
stroke(100);
line(x[0], y[0], x[1], y[1]);
line(x[2], y[2], x[3], y[3]);
// the anchor and control points
stroke(0);
fill(0);
for (int i = 0; i< 4; i++) {
if (i == 0 || i == 3) {
fill(255, 100, 10);
rectMode(CENTER);
rect(x[i], y[i], 5, 5);
} else {
fill(0);
ellipse(x[i], y[i], 5, 5);
}
}
 
// permit dragging
for (int i = 0; i < 4; i++) {
if (permitDrag[i]) {
x[i] = mouseX;
y[i] = mouseY;
}
}
}
 
void mouseReleased () {
for (int i = 0; i < 4; i++) {
permitDrag[i] = false;
}
}
 
void mousePressed () {
for (int i = 0; i < 4; i++) {
if (mouseX >= x[i]-5 && mouseX <= x[i]+10 && mouseY >= y[i]-5 && mouseY <= y[i]+10) {
permitDrag[i] = true;
}
}
}
 
// hand curser when dragging over points
void mouseMoved () {
cursor(ARROW);
for (int i = 0; i < 4; i++) {
if (mouseX >= x[i]-5 && mouseX <= x[i]+10 && mouseY >= y[i]-5 && mouseY <= y[i]+10) {
cursor(HAND);
}
}
}
</syntaxhighlight>
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">Procedure cubic_bezier(img, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y, Color, n_seg)
Protected i
Protected.f t, t1, a, b, c, d
Line 750 ⟶ 1,822:
Repeat
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow</langsyntaxhighlight>
 
=={{header|Python}}==
{{works with|Python|3.1}}
 
Extending the example given [[Bresenham's line algorithm#Python|here]] and using the algorithm from the C solution above:
<langsyntaxhighlight lang="python">def cubicbezier(self, x0, y0, x1, y1, x2, y2, x3, y3, n=20):
pts = []
for i in range(n+1):
Line 801 ⟶ 1,872:
| |
+-----------------+
'''</langsyntaxhighlight>
 
=={{header|R}}==
<langsyntaxhighlight Rlang="r"># x, y: the x and y coordinates of the hull points
# n: the number of points in the curve.
bezierCurve <- function(x, y, n=10)
Line 842 ⟶ 1,912:
y <- 1:6
plot(x, y, "o", pch=20)
points(bezierCurve(x,y,20), type="l", col="red")</langsyntaxhighlight>
 
=={{header|Racket}}==
<langsyntaxhighlight lang="racket">
#lang racket
(require racket/draw)
Line 872 ⟶ 1,941:
(draw-lines dc (bezier-points '(16 1) '(1 4) '(3 16) '(15 11)))
bm
</syntaxhighlight>
</lang>
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2017.09}}
Uses pieces from [[Bitmap#Raku| Bitmap]], and [[Bitmap/Bresenham's_line_algorithm#Raku| Bresenham's line algorithm]] tasks. They are included here to make a complete, runnable program.
 
<syntaxhighlight lang="raku" line>class Pixel { has UInt ($.R, $.G, $.B) }
class Bitmap {
has UInt ($.width, $.height);
has Pixel @!data;
 
method fill(Pixel $p) {
@!data = $p.clone xx ($!width*$!height)
}
method pixel(
$i where ^$!width,
$j where ^$!height
--> Pixel
) is rw { @!data[$i + $j * $!width] }
 
method set-pixel ($i, $j, Pixel $p) {
self.pixel($i, $j) = $p.clone;
}
method get-pixel ($i, $j) returns Pixel {
self.pixel($i, $j);
}
 
method line(($x0 is copy, $y0 is copy), ($x1 is copy, $y1 is copy), $pix) {
my $steep = abs($y1 - $y0) > abs($x1 - $x0);
if $steep {
($x0, $y0) = ($y0, $x0);
($x1, $y1) = ($y1, $x1);
}
if $x0 > $x1 {
($x0, $x1) = ($x1, $x0);
($y0, $y1) = ($y1, $y0);
}
my $Δx = $x1 - $x0;
my $Δy = abs($y1 - $y0);
my $error = 0;
my $Δerror = $Δy / $Δx;
my $y-step = $y0 < $y1 ?? 1 !! -1;
my $y = $y0;
for $x0 .. $x1 -> $x {
if $steep {
self.set-pixel($y, $x, $pix);
} else {
self.set-pixel($x, $y, $pix);
}
$error += $Δerror;
if $error >= 0.5 {
$y += $y-step;
$error -= 1.0;
}
}
}
 
method dot (($px, $py), $pix, $radius = 2) {
for $px - $radius .. $px + $radius -> $x {
for $py - $radius .. $py + $radius -> $y {
self.set-pixel($x, $y, $pix) if ( $px - $x + ($py - $y) * i ).abs <= $radius;
}
}
}
 
method cubic ( ($x1, $y1), ($x2, $y2), ($x3, $y3), ($x4, $y4), $pix, $segments = 30 ) {
my @line-segments = map -> $t {
my \a = (1-$t)³;
my \b = $t * (1-$t)² * 3;
my \c = $t² * (1-$t) * 3;
my \d = $t³;
(a*$x1 + b*$x2 + c*$x3 + d*$x4).round(1),(a*$y1 + b*$y2 + c*$y3 + d*$y4).round(1)
}, (0, 1/$segments, 2/$segments ... 1);
for @line-segments.rotor(2=>-1) -> ($p1, $p2) { self.line( $p1, $p2, $pix) };
}
 
method data { @!data }
}
 
role PPM {
method P6 returns Blob {
"P6\n{self.width} {self.height}\n255\n".encode('ascii')
~ Blob.new: flat map { .R, .G, .B }, self.data
}
}
 
sub color( $r, $g, $b) { Pixel.new(R => $r, G => $g, B => $b) }
 
my Bitmap $b = Bitmap.new( width => 600, height => 400) but PPM;
 
$b.fill( color(2,2,2) );
 
my @points = (85,390), (5,5), (580,370), (270,10);
 
my %seen;
my $c = 0;
for @points.permutations -> @this {
%seen{@this.reverse.join.Str}++;
next if %seen{@this.join.Str};
$b.cubic( |@this, color(255-$c,127,$c+=22) );
}
 
@points.map: { $b.dot( $_, color(255,0,0), 3 )}
 
$*OUT.write: $b.P6;</syntaxhighlight>
 
See [https://github.com/thundergnat/rc/blob/master/img/Bezier-cubic-perl6.png example image here], (converted to a .png as .ppm format is not widely supported).
=={{header|Ruby}}==
{{trans|Tcl}}
Line 879 ⟶ 2,053:
Requires code from the [[Bitmap#Ruby|Bitmap]] and [[Bitmap/Bresenham's line algorithm#Ruby Bresenham's line algorithm]] tasks
 
<langsyntaxhighlight lang="ruby">class Pixmap
def draw_bezier_curve(points, colour)
# ensure the points are increasing along the x-axis
Line 919 ⟶ 2,093:
]
points.each {|p| bitmap.draw_circle(p, 3, RGBColour::RED)}
bitmap.draw_bezier_curve(points, RGBColour::BLUE)</langsyntaxhighlight>
 
=={{header|Tcl}}==
{{libheader|Tk}}
This solution can be applied to any number of points. Uses code from [[Basic_bitmap_storage#Tcl|Basic bitmap storage]] (<tt>newImage</tt>, <tt>fill</tt>), [[Bresenham's_line_algorithm#Tcl|Bresenham's line algorithm]] (<tt>drawLine</tt>), and [[Midpoint_circle_algorithm#Tcl|Midpoint circle algorithm]] (<tt>drawCircle</tt>)
<langsyntaxhighlight lang="tcl">package require Tcl 8.5
package require Tk
 
Line 983 ⟶ 2,156:
button .new -command [list newbezier $degree .img] -text New
button .exit -command exit -text Exit
pack .new .img .exit -side top</langsyntaxhighlight>
Results in:
 
[[Image:Tcl_cubic_bezier.png]]
 
=={{header|TI-89 BASIC}}==
 
{{TI-image-task}}
 
<langsyntaxhighlight lang="ti89b">Define cubic(p1,p2,p3,p4,segs) = Prgm
Local i,t,u,prev,pt
0 → pt
Line 1,004 ⟶ 2,176:
EndIf
EndFor
EndPrgm</langsyntaxhighlight>
=={{header|Wren}}==
{{libheader|DOME}}
Requires version 1.3.0 of DOME or later.
<syntaxhighlight lang="wren">import "graphics" for Canvas, ImageData, Color, Point
import "dome" for Window
 
class Game {
static bmpCreate(name, w, h) { ImageData.create(name, w, h) }
 
static bmpFill(name, col) {
var image = ImageData[name]
for (x in 0...image.width) {
for (y in 0...image.height) image.pset(x, y, col)
}
}
 
static bmpPset(name, x, y, col) { ImageData[name].pset(x, y, col) }
 
static bmpPget(name, x, y) { ImageData[name].pget(x, y) }
 
static bmpLine(name, x0, y0, x1, y1, col) {
var dx = (x1 - x0).abs
var dy = (y1 - y0).abs
var sx = (x0 < x1) ? 1 : -1
var sy = (y0 < y1) ? 1 : -1
var err = ((dx > dy ? dx : - dy) / 2).floor
while (true) {
bmpPset(name, x0, y0, col)
if (x0 == x1 && y0 == y1) break
var e2 = err
if (e2 > -dx) {
err = err - dy
x0 = x0 + sx
}
if (e2 < dy) {
err = err + dx
y0 = y0 + sy
}
}
}
 
static bmpCubicBezier(name, p1, p2, p3, p4, col, n) {
var pts = List.filled(n+1, null)
for (i in 0..n) {
var t = i / n
var u = 1 - t
var a = u * u * u
var b = 3 * t * u * u
var c = 3 * t * t * u
var d = t * t * t
var px = (a * p1.x + b * p2.x + c * p3.x + d * p4.x).truncate
var py = (a * p1.y + b * p2.y + c * p3.y + d * p4.y).truncate
pts[i] = Point.new(px, py, col)
}
for (i in 0...n) {
var j = i + 1
bmpLine(name, pts[i].x, pts[i].y, pts[j].x, pts[j].y, col)
}
}
static init() {
Window.title = "Cubic Bézier curve"
var size = 200
Window.resize(size, size)
Canvas.resize(size, size)
var name = "cubic"
var bmp = bmpCreate(name, size, size)
bmpFill(name, Color.white)
var p1 = Point.new(160, 10)
var p2 = Point.new( 10, 40)
var p3 = Point.new( 30, 160)
var p4 = Point.new(150, 110)
bmpCubicBezier(name, p1, p2, p3, p4, Color.darkblue, 20)
bmp.draw(0, 0)
}
 
static update() {}
 
static draw(alpha) {}
}</syntaxhighlight>
 
=={{header|XPL0}}==
[[File:CubicXPL0.png|right]]
<langsyntaxhighlight XPL0lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations
func real Power(X, Y); \X raised to the Y power; (X > 0.0)
real X, Y;
return Exp(Y * Ln(X));
 
proc Bezier(P0, P1, P2, P3); \Draw cubic Bezier curve
Line 1,017 ⟶ 2,266:
def Segments = 8;
int I;
real S1, T, AT2, BT3, CU, DU2, U3, B, C, X, Y;
[Move(fix(P0(0)), fix(P0(1)));
S1:= 1./float(Segments);
T:= 0.;
for I:= 1 to Segments-1 do
[T:= float(I)/float(Segments)T+S1;
AT2:= Power((1.-T), 3.)*T;
BT3:= 3.T2*T*Power((1.-T), 2.);
CU:= 3.*Power(T, 2.)*(1.-T);
DU2:= Power(T, 3.)U*U;
XU3:= AU2*P0(0) + B*P1(0) + C*P2(0) + D*P3(0)U;
YB:= A3.*P0(1) + B*P1(1) + C*P2(1) + DT*P3(1)U2;
C:= 3.*T2*U;
X:= U3*P0(0) + B*P1(0) + C*P2(0) + T3*P3(0);
Y:= U3*P0(1) + B*P1(1) + C*P2(1) + T3*P3(1);
Line(fix(X), fix(Y), $00FFFF); \cyan line segments
];
Line 1,040 ⟶ 2,294:
if ChIn(1) then []; \wait for keystroke
SetVid(3); \restore normal text display
]</langsyntaxhighlight>
=={{header|zkl}}==
[[File:CubicXPL0.png|right]]
Image cribbed from XPL0
 
Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
 
Add this to the PPM class:
<syntaxhighlight lang="zkl"> fcn cBezier(p0x,p0y, p1x,p1y, p2x,p2y, p3x,p3y, rgb, numPts=500){
numPts.pump(Void,'wrap(t){ // B(t)
t=t.toFloat()/numPts; t1:=(1.0 - t);
a:=t1*t1*t1; b:=t*t1*t1*3; c:=t1*t*t*3; d:=t*t*t;
x:=a*p0x + b*p1x + c*p2x + d*p3x + 0.5;
y:=a*p0y + b*p1y + c*p2y + d*p3y + 0.5;
__sSet(rgb,x,y);
});
}</syntaxhighlight>
Doesn't use line segments, they don't seem like an improvement.
<syntaxhighlight lang="zkl">bitmap:=PPM(200,150,0xff|ff|ff);
bitmap.cBezier(0,149, 30,50, 120,130, 160,30, 0);
bitmap.write(File("foo.ppm","wb"));</syntaxhighlight>
{{omit from|AWK}}
{{omit from|GUISS}}
{{omit from|PARI/GP}}
Anonymous user