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

no edit summary
imported>Chinhouse
No edit summary
(85 intermediate revisions by 44 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 curvescurve'''
([http[wp://en.wikipedia.org/wiki/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 57 ⟶ 305:
=={{header|ALGOL 68}}==
{{trans|Ada}}
{{works with|ALGOL 68|Revision 1 - one minor extension to language used - PRAGMA READ, similar to C's #include directive.}}
 
{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-2.6 algol68g-2.6].}}
{{works with|ALGOL 68|Standard - '''pragmat''' '''read''' is an extension}}
{{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''.}}
{{works with|ALGOL 68G|Any - tested with release mk15-0.8b.fc9.i386}}
'''File: prelude/Bitmap/Bezier_curves/Cubic.a68'''<syntaxhighlight lang="algol68"># -*- coding: utf-8 -*- #
<!-- {{does not work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release 1.8.8d.fc9.i386 - '''pragmat''' '''read''' is not part of algol68rs}} -->
<lang algol68>PRAGMAT READ "Bresenhams_line_algorithm.a68" PRAGMAT;
 
cubic bezier OF class image :=
Line 86 ⟶ 333:
END # cubic bezier #;
 
SKIP</syntaxhighlight>'''File: test/Bitmap/Bezier_curves/Cubic.a68'''<syntaxhighlight lang="algol68">#!/usr/bin/a68g --script #
#
# -*- coding: utf-8 -*- #
The following test
#
PR READ "prelude/Bitmap.a68" PR; # c.f. [[rc:Bitmap]] #
IF test THEN
PR READ "prelude/Bitmap/Bresenhams_line_algorithm.a68" PR; # c.f. [[rc:Bitmap/Bresenhams_line_algorithm]] #
PR READ "prelude/Bitmap/Bezier_curves/Cubic.a68" PR;
 
# The following test #
test:(
REF IMAGE x = INIT LOC[16,16]PIXEL;
(fill OF class image)(x, (white OF class image));
(cubic bezier OF class image)(x, (16, 1), (1, 4), (3, 16), (15, 11), (black OF class image), EMPTY);
(print OF class image) (x)
)</syntaxhighlight>'''Output:'''
FI</lang>
Output:
<pre>
ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
Line 114 ⟶ 365:
000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
</pre>
=={{header|ATS}}==
See [[Bresenham_tasks_in_ATS]].
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
[[Image:beziercubic_bbc.gif|right]]
<syntaxhighlight lang="bbcbasic"> Width% = 200
Height% = 200
REM Set window size:
VDU 23,22,Width%;Height%;8,16,16,128
REM Draw cubic Bézier curve:
PROCbeziercubic(160,150, 10,120, 30,0, 150,50, 20, 0,0,0)
END
DEF PROCbeziercubic(x1,y1,x2,y2,x3,y3,x4,y4,n%,r%,g%,b%)
LOCAL i%, t, t1, a, b, c, d, p{()}
DIM p{(n%) x%,y%}
FOR i% = 0 TO n%
t = i% / n%
t1 = 1 - t
a = t1^3
b = 3 * t * t1^2
c = 3 * t^2 * t1
d = t^3
p{(i%)}.x% = INT(a * x1 + b * x2 + c * x3 + d * x4 + 0.5)
p{(i%)}.y% = INT(a * y1 + b * y2 + c * y3 + d * y4 + 0.5)
NEXT
FOR i% = 0 TO n%-1
PROCbresenham(p{(i%)}.x%,p{(i%)}.y%,p{(i%+1)}.x%,p{(i%+1)}.y%, \
\ r%,g%,b%)
NEXT
ENDPROC
DEF PROCbresenham(x1%,y1%,x2%,y2%,r%,g%,b%)
LOCAL dx%, dy%, sx%, sy%, e
dx% = ABS(x2% - x1%) : sx% = SGN(x2% - x1%)
dy% = ABS(y2% - y1%) : sy% = SGN(y2% - y1%)
IF dx% < dy% e = dx% / 2 ELSE e = dy% / 2
REPEAT
PROCsetpixel(x1%,y1%,r%,g%,b%)
IF x1% = x2% IF y1% = y2% EXIT REPEAT
IF dx% > dy% THEN
x1% += sx% : e -= dy% : IF e < 0 e += dx% : y1% += sy%
ELSE
y1% += sy% : e -= dx% : IF e < 0 e += dy% : x1% += sx%
ENDIF
UNTIL FALSE
ENDPROC
DEF PROCsetpixel(x%,y%,r%,g%,b%)
COLOUR 1,r%,g%,b%
GCOL 1
LINE x%*2,y%*2,x%*2,y%*2
ENDPROC</syntaxhighlight>
 
=={{header|C}}==
"Interface" <tt>imglib.h</tt>.
 
<langsyntaxhighlight lang="c">void cubic_bezier(
image img,
unsigned int x1, unsigned int y1,
Line 126 ⟶ 435:
color_component r,
color_component g,
color_component b );</langsyntaxhighlight>
 
<langsyntaxhighlight lang="c">#include <math.h>
 
/* number of segments for the curve */
Line 181 ⟶ 490:
}
#undef plot
#undef line</langsyntaxhighlight>
=={{header|D}}==
This solution uses two modules, from the Grayscale image and Bresenham's line algorithm Tasks.
<syntaxhighlight lang="d">import grayscale_image, bitmap_bresenhams_line_algorithm;
 
struct Pt { int x, y; } // Signed.
 
void cubicBezier(size_t nSegments=20, Color)
(Image!Color im,
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 / double(nSegments),
a = (1.0 - t) ^^ 3,
b = 3.0 * t * (1.0 - t) ^^ 2,
c = 3.0 * t ^^ 2 * (1.0 - t),
d = t ^^ 3;
 
alias T = typeof(Pt.x);
p = Pt(cast(T)(a * p1.x + b * p2.x + c * p3.x + d * p4.x),
cast(T)(a * p1.y + b * p2.y + c * p3.y + d * p4.y));
}
 
foreach (immutable i, immutable p; points[0 .. $ - 1])
im.drawLine(p.x, p.y, points[i + 1].x, points[i + 1].y, color);
}
 
void main() {
auto im = new Image!Gray(17, 17);
im.clear(Gray.white);
im.cubicBezier(Pt(16, 1), Pt(1, 4), Pt(3, 16), Pt(15, 11),
Gray.black);
im.textualShow();
}</syntaxhighlight>
{{out}}
<pre>.................
.............####
.........####....
........#........
.......#.........
......#..........
......#..........
.....#...........
.....#...........
.....#...........
.....#...........
......##....####.
........####.....
.................
.................
.................
.................</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#">
/// Uses Vector<float> from Microsoft.FSharp.Math (in F# PowerPack)
module CubicBezier
 
/// Create bezier curve from p1 to p4, using the control points p2, p3
/// Returns the requested number of segments
let cubic_bezier (p1:vector) (p2:vector) (p3:vector) (p4:vector) segments =
[0 .. segments - 1]
|> List.map(fun i ->
let t = float i / float segments
let a = (1. - t) ** 3.
let b = 3. * t * ((1. - t) ** 2.)
let c = 3. * (t ** 2.) * (1. - t)
let d = t ** 3.
let x = a * p1.[0] + b * p2.[0] + c * p3.[0] + d * p4.[0]
let y = a * p1.[1] + b * p2.[1] + c * p3.[1] + d * p4.[1]
vector [x; y])
 
</syntaxhighlight>
<syntaxhighlight lang="f#">
// For rendering..
let drawPoints points (canvas:System.Windows.Controls.Canvas) =
let addLineToScreen (v1:vector) (v2:vector) =
canvas.Children.Add(new System.Windows.Shapes.Line(X1 = v1.[0],
Y1 = -v1.[1],
X2 = v2.[0],
Y2 = -v2.[1],
StrokeThickness = 2.)) |> ignore
let renderPoint (previous:vector) (current:vector) =
addLineToScreen previous current
current
 
points |> List.fold renderPoint points.Head
</syntaxhighlight>
=={{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:'''
<syntaxhighlight lang="qbasic">#DEFINE WM_LBUTTONDOWN 513
#DEFINE WM_CLOSE 16
 
FBSLSETTEXT(ME, "Bezier Cubic")
FBSLSETFORMCOLOR(ME, RGB(0, 255, 255)) ' Cyan: persistent background color
DRAWWIDTH(5) ' Adjust point size
FBSL.GETDC(ME) ' Use volatile FBSL.GETDC below to avoid extra assignments
 
RESIZE(ME, 0, 0, 235, 235)
CENTER(ME)
SHOW(ME)
 
DIM Height AS INTEGER
FBSL.GETCLIENTRECT(ME, 0, 0, 0, Height)
 
BEGIN EVENTS
SELECT CASE CBMSG
CASE WM_LBUTTONDOWN: BezierCube(160, 150, 10, 120, 30, 0, 150, 50, 20) ' Draw
CASE WM_CLOSE: FBSL.RELEASEDC(ME, FBSL.GETDC) ' Clean up
END SELECT
END EVENTS
 
SUB BezierCube(x1, y1, x2, y2, x3, y3, x4, y4, n)
TYPE POINTAPI
x AS INTEGER
y AS INTEGER
END TYPE
DIM t, t1, a, b, c, d, p[n] AS POINTAPI
FOR DIM i = 0 TO n
t = i / n: t1 = 1 - t
a = t1 ^ 3
b = 3 * t * t1 ^ 2
c = 3 * t ^ 2 * t1
d = t ^ 3
p[i].x = a * x1 + b * x2 + c * x3 + d * x4 + 0.5
p[i].y = Height - (a * y1 + b * y2 + c * y3 + d * y4 + 0.5)
NEXT
FOR i = 0 TO n - 1
Bresenham(p[i].x, p[i].y, p[i + 1].x, p[i + 1].y)
NEXT
SUB Bresenham(x0, y0, x1, y1)
DIM dx = ABS(x0 - x1), sx = SGN(x0 - x1)
DIM dy = ABS(y0 - y1), sy = SGN(y0 - y1)
DIM tmp, er = IIF(dx > dy, dx, -dy) / 2
WHILE NOT (x0 = x1 ANDALSO y0 = y1)
PSET(FBSL.GETDC, x0, y0, &HFF) ' Red: Windows stores colors in BGR order
tmp = er
IF tmp > -dx THEN: er = er - dy: x0 = x0 + sx: END IF
IF tmp < +dy THEN: er = er + dx: y0 = y0 + sy: END IF
WEND
END SUB
END SUB</syntaxhighlight>
'''Output:''' [[File:FBSLBezierCube.PNG]]
=={{header|Fortran}}==
{{trans|C}}
Line 188 ⟶ 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 199 ⟶ 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 214 ⟶ 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}}
<syntaxhighlight lang="go">package raster
 
const b3Seg = 30
 
func (b *Bitmap) Bézier3(x1, y1, x2, y2, x3, y3, x4, y4 int, p Pixel) {
var px, py [b3Seg + 1]int
fx1, fy1 := float64(x1), float64(y1)
fx2, fy2 := float64(x2), float64(y2)
fx3, fy3 := float64(x3), float64(y3)
fx4, fy4 := float64(x4), float64(y4)
for i := range px {
d := float64(i) / b3Seg
a := 1 - d
b, c := a * a, d * d
a, b, c, d = a*b, 3*b*d, 3*a*c, c*d
px[i] = int(a*fx1 + b*fx2 + c*fx3 + d*fx4)
py[i] = int(a*fy1 + b*fy2 + c*fy3 + d*fy4)
}
x0, y0 := px[0], py[0]
for i := 1; i <= b3Seg; i++ {
x1, y1 := px[i], py[i]
b.Line(x0, y0, x1, y1, p)
x0, y0 = x1, y1
}
}
 
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())
}</syntaxhighlight>
Demonstration program:
[[File:GoBez3.png|thumb|right]]
<syntaxhighlight lang="go">package main
 
import (
"fmt"
"raster"
)
 
func main() {
b := raster.NewBitmap(400, 300)
b.FillRgb(0xffefbf)
b.Bézier3Rgb(20, 200, 700, 50, -300, 50, 380, 150, raster.Rgb(0x3f8fef))
if err := b.WritePpmFile("bez3.ppm"); err != nil {
fmt.Println(err)
}
}</syntaxhighlight>
=={{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 240 ⟶ 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|Java}}==
Using the BasicBitmapStorage class from the [[Bitmap]] task to produce a runnable program.
<syntaxhighlight lang ="java">
 
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">
function bezierCubic(obj,pixel_0,pixel_1,pixel_2,pixel_3,color,varargin)
 
if( isempty(varargin) )
resolution = 20;
else
resolution = varargin{1};
end
 
%Calculate time axis
time = (0:1/resolution:1)';
timeMinus = 1-time;
 
%The formula for the curve is expanded for clarity, the lack of
%loops is because its calculation has been vectorized
curve = (timeMinus).^3*pixel_0; %First term of polynomial
curve = curve + (3.*time.*timeMinus.^2)*pixel_1; %second term of polynomial
curve = curve + (3.*timeMinus.*time.^2)*pixel_2; %third term of polynomial
curve = curve + time.^3*pixel_3; %Fourth term of polynomial
 
curve = round(curve); %round each of the points to the nearest integer
 
%connect each of the points in the curve with a line using the
%Bresenham Line algorithm
for i = (1:length(curve)-1)
obj.bresenhamLine(curve(i,:),curve(i+1,:),color);
end
assignin('caller',inputname(1),obj); %saves the changes to the object
end
</syntaxhighlight>
 
Sample usage:
This will generate the image example for the PHP solution.
<syntaxhighlight 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>
 
=={{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 291 ⟶ 1,586:
let line = draw_line ~img ~color in
let by_pair li f =
ignore (List.fold_left (fun prev x -> f prev x; x) (List.hd li) (List.tl li))
let rec aux prev = function
| [] -> ()
| x::xs ->
f prev x;
aux x xs
in
aux (List.hd li) (List.tl li)
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 307 ⟶ 1,630:
{{trans|Python}}
 
{{works with|PHP| with GD library4.3.0}}
 
{{libheader|GD}}
 
Outputs image to the right directly to browser or stdout.
 
<syntaxhighlight lang="php"><?
<lang php>
<?
 
$image = imagecreate(200, 200);
Line 341 ⟶ 1,665:
}
}
</syntaxhighlight>
</lang>
=={{header|PicoLisp}}==
This uses the 'brez' line drawing function from
[[Bitmap/Bresenham's line algorithm#PicoLisp]].
<syntaxhighlight lang="picolisp">(scl 6)
 
(de cubicBezier (Img N X1 Y1 X2 Y2 X3 Y3 X4 Y4)
(let (R (* N N N) X X1 Y Y1 DX 0 DY 0)
(for I N
(let
(J (- N I)
A (*/ 1.0 J J J R)
B (*/ 3.0 I J J R)
C (*/ 3.0 I I J R)
D (*/ 1.0 I I I R) )
(brez Img
X
Y
(setq DX
(-
(+ (*/ A X1 1.0) (*/ B X2 1.0) (*/ C X3 1.0) (*/ D X4 1.0))
X ) )
(setq DY
(-
(+ (*/ A Y1 1.0) (*/ B Y2 1.0) (*/ C Y3 1.0) (*/ D Y4 1.0))
Y ) ) )
(inc 'X DX)
(inc 'Y DY) ) ) ) )</syntaxhighlight>
Test:
<syntaxhighlight lang="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
(prinl "P1")
(prinl 300 " " 200)
(mapc prinl Img) ) )
 
(call 'display "img.pbm")</syntaxhighlight>
=={{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}}==
<syntaxhighlight lang="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
Dim pts.POINT(n_seg)
For i = 0 To n_seg
t = i / n_seg
t1 = 1.0 - t
a = Pow(t1, 3)
b = 3.0 * t * Pow(t1, 2)
c = 3.0 * Pow(t, 2) * t1
d = Pow(t, 3)
pts(i)\x = a * p1x + b * p2x + c * p3x + d * p4x
pts(i)\y = a * p1y + b * p2y + c * p3y + d * p4y
Next
StartDrawing(ImageOutput(img))
FrontColor(Color)
For i = 0 To n_seg - 1
BresenhamLine(pts(i)\x, pts(i)\y, pts(i + 1)\x, pts(i + 1)\y) ;this calls the implementation of a draw_line routine
Next
StopDrawing()
EndProcedure
 
Define w, h, img
w = 200: h = 200: img = 1
CreateImage(img, w, h) ;img is internal id of the image
 
OpenWindow(0, 0, 0, w, h,"Bezier curve, cubic", #PB_Window_SystemMenu)
cubic_bezier(1, 160,10, 10,40, 30,160, 150,110, RGB(255, 255, 255), 20)
ImageGadget(0, 0, 0, w, h, ImageID(1))
 
Define event
Repeat
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow</syntaxhighlight>
=={{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 358 ⟶ 1,838:
x = int(a * x0 + b * x1 + c * x2 + d * x3)
y = int(a * y0 + b * y1 + c * y2 + d * y3)
pts.addappend( (x, y) )
for i in range(n):
self.line(pts[i][0], pts[i][1], pts[i+1][0], pts[i+1][1])
Line 392 ⟶ 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 433 ⟶ 1,912:
y <- 1:6
plot(x, y, "o", pch=20)
points(bezierCurve(x,y,20), type="l", col="red")</langsyntaxhighlight>
=={{header|Racket}}==
<syntaxhighlight lang="racket">
#lang racket
(require racket/draw)
 
(define (draw-line dc p q)
(match* (p q) [((list x y) (list s t)) (send dc draw-line x y s t)]))
 
(define (draw-lines dc ps)
(void
(for/fold ([p0 (first ps)]) ([p (rest ps)])
(draw-line dc p0 p)
p)))
 
(define (int t p q)
(define ((int1 t) x0 x1) (+ (* (- 1 t) x0) (* t x1)))
(map (int1 t) p q))
(define (bezier-points p0 p1 p2 p3)
(for/list ([t (in-range 0.0 1.0 (/ 1.0 20))])
(int t (int t p0 p1) (int t p2 p3))))
 
(define bm (make-object bitmap% 17 17))
(define dc (new bitmap-dc% [bitmap bm]))
(send dc set-smoothing 'unsmoothed)
(send dc set-pen "red" 1 'solid)
(draw-lines dc (bezier-points '(16 1) '(1 4) '(3 16) '(15 11)))
bm
</syntaxhighlight>
=={{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}}
 
<lang ruby>class Pixmap
Requires code from the [[Bitmap#Ruby|Bitmap]] and [[Bitmap/Bresenham's line algorithm#Ruby Bresenham's line algorithm]] tasks
 
<syntaxhighlight lang="ruby">class Pixmap
def draw_bezier_curve(points, colour)
# ensure the points are increasing along the x-axis
Line 477 ⟶ 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 541 ⟶ 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 562 ⟶ 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]]
<syntaxhighlight lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations
 
proc Bezier(P0, P1, P2, P3); \Draw cubic Bezier curve
real P0, P1, P2, P3;
def Segments = 8;
int I;
real S1, T, T2, T3, U, U2, 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:= T+S1;
T2:= T*T;
T3:= T2*T;
U:= 1.-T;
U2:= U*U;
U3:= U2*U;
B:= 3.*T*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(fix(P3(0)), fix(P3(1)), $00FFFF);
Point(fix(P0(0)), fix(P0(1)), $FF0000); \red control points
Point(fix(P1(0)), fix(P1(1)), $FF0000);
Point(fix(P2(0)), fix(P2(1)), $FF0000);
Point(fix(P3(0)), fix(P3(1)), $FF0000);
];
 
[SetVid($112); \set 640x480x24 video graphics
Bezier([0., 0.], [30., 100.], [120., 20.], [160., 120.]);
if ChIn(1) then []; \wait for keystroke
SetVid(3); \restore normal text display
]</syntaxhighlight>
=={{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