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

(→‎{{header|Perl 6}}: Updated to show that the end and control points can be in any order)
imported>Chinhouse
 
(27 intermediate revisions by 13 users not shown)
Line 3:
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 one]], draw a ''quadratic bezier curve''
([[wp:Bezier_curves#Quadratic_B.C3.A9zier_curves|definition on Wikipedia]]).
=={{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 QuadraticBezier(RgbImage POINTER img
IntPoint POINTER p1,p2,p3 RGB POINTER col)
INT i,n=[20],prevX,prevY,nextX,nextY
REAL one,two,ri,rn,rt,ra,rb,rc,tmp1,tmp2,tmp3
REAL x1,y1,x2,y2,x3,y3
 
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(1,one) IntToReal(2,two)
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,ra) ;a=(1-t)^2
RealMult(two,rt,tmp2) ;tmp2=2*t
RealMult(tmp2,tmp1,rb) ;b=2*t*(1-t)
 
RealMult(rt,rt,rc) ;c=t^2
 
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
nextX=Round(tmp2)
 
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
nextY=Round(tmp2)
 
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
 
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=47 p2.y=39
p3.x=69 p3.y=12
RgbLine(img,p1.x,p1.y,p2.x,p2.y,blue)
RgbLine(img,p2.x,p2.y,p3.x,p3.y,blue)
QuadraticBezier(img,p1,p2,p3,yellow)
SetRgbPixel(img,p1.x,p1.y,violet)
SetRgbPixel(img,p2.x,p2.y,violet)
SetRgbPixel(img,p3.x,p3.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_quadratic.png Screenshot from Atari 8-bit computer]
=={{header|Ada}}==
<langsyntaxhighlight lang="ada">procedure Quadratic_Bezier
( Picture : in out Image;
P1, P2, P3 : Point;
Line 28 ⟶ 144:
Line (Picture, Points (I), Points (I + 1), Color);
end loop;
end Quadratic_Bezier;</langsyntaxhighlight>
The following test
<langsyntaxhighlight lang="ada"> X : Image (1..16, 1..16);
begin
Fill (X, White);
Quadratic_Bezier (X, (8, 2), (13, 8), (2, 15), Black);
Print (X);</langsyntaxhighlight>
should produce;
<pre>
Line 54 ⟶ 170:
 
</pre>
=={{header|ATS}}==
See [[Bresenham_tasks_in_ATS]].
 
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
[[Image:bezierquad_bbc.gif|right]]
<langsyntaxhighlight lang="bbcbasic"> Width% = 200
Height% = 200
Line 107 ⟶ 226:
GCOL 1
LINE x%*2,y%*2,x%*2,y%*2
ENDPROC</langsyntaxhighlight>
 
=={{header|C}}==
Line 113 ⟶ 232:
Interface (to be added to all other to make the final <tt>imglib.h</tt>):
 
<langsyntaxhighlight lang="c">void quad_bezier(
image img,
unsigned int x1, unsigned int y1,
Line 120 ⟶ 239:
color_component r,
color_component g,
color_component b );</langsyntaxhighlight>
 
Implementation:
 
<langsyntaxhighlight lang="c">#include <math.h>
 
/* number of segments for the curve */
Line 173 ⟶ 292:
}
#undef plot
#undef line</langsyntaxhighlight>
 
 
 
=={{header|Commodore Basic}}==
<syntaxhighlight lang="basic">
10 rem bezier curve algorihm
20 rem translated from purebasic
30 ns=25 : rem num segments
40 dim pt(ns,2) : rem points in line
50 sc=1024 : rem start of screen memory
60 sw=40 : rem screen width
70 sh=25 : rem screen height
80 pc=42 : rem plot character '*'
90 dim bp(2,1) : rem bezier curve points
100 bp(0,0)=1:bp(1,0)=70:bp(2,0)=1
110 bp(0,1)=1:bp(1,1)=8:bp(2,1)=23
120 dim pt%(ns,2) : rem individual lines in curve
130 gosub 3000
140 end
1000 rem plot line
1010 se=0 : rem 0 = steep 1 = !steep
1020 if abs(y1-y0)>abs(x1-x0) then se=1:tp=y0:y0=x0:x0=tp:tp=y1:y1=x1:x1=tp
1030 if x0>x1 then tp=x1:x1=x0:x0=tp:tp=y1:y1=y0:y0=tp
1040 dx=x1-x0
1050 dy=abs(y1-y0)
1060 er=dx/2
1070 y=y0
1080 ys=-1
1090 if y0<y1 then ys = 1
1100 for x=x0 to x1
1110 if se=1 then p0=y: p1=x:gosub 2000:goto 1130
1120 p0=x: p1=y: gosub 2000
1130 er=er-dy
1140 if er<0 then y=y+ys:er=er+dx
1150 next x
1160 return
2000 rem plot individual point
2010 rem p0 == plot point x
2020 rem p1 == plot point y
2030 sl=p0+(p1*sw)
2040 rem make sure we dont write beyond screen memory
2050 if sl<(sw*sh) then poke sc+sl,pc
2060 return
3000 rem bezier curve
3010 for i=0 to ns
3020 t=i/ns
3030 t1=1.0-t
3040 a=t1^2
3050 b=2.0*t*t1
3060 c=t^2
3070 pt(i,0)=a*bp(0,0)+b*bp(1,0)+c*bp(2,0)
3080 pt(i,1)=a*bp(0,1)+b*bp(1,1)+c*bp(2,1)
3090 next i
3100 for i=0 to ns-1
3110 x0=int(pt(i,0))
3120 y0=int(pt(i,1))
3130 x1=int(pt(i+1,0))
3140 y1=int(pt(i+1,1))
3150 gosub 1000
3160 next i
3170 return
</syntaxhighlight>
[https://www.worldofchris.com/assets/c64-bezier-curve.png Screenshot of Bézier curve on C64]
=={{header|D}}==
This solution uses two modules, from the Grayscale image and the Bresenham's line algorithm Tasks.
<langsyntaxhighlight lang="d">import grayscale_image, bitmap_bresenhams_line_algorithm;
 
struct Pt { int x, y; } // Signed.
Line 205 ⟶ 386:
im.quadraticBezier(Pt(1,10), Pt(25,27), Pt(15,2), Gray.black);
im.textualShow();
}</langsyntaxhighlight>
{{out}}
<pre>....................
Line 228 ⟶ 409:
....................</pre>
 
 
=={{header|Delphi}}==
{{works with|Delphi|6.0}}
{{libheader|SysUtils,StdCtrls}}
[[File:DelphiQuadBezier.png|frame|none]]
 
This code uses a Quadratic Bézier curve to create a Cardinal Spline, which is a much easier spline to use. You just provide a series of points and the spline will honor those points while creating a smooth curline line between the points.
 
<syntaxhighlight lang="Delphi">
 
{This code would normally be in a library, but is presented here for clarity}
 
type T2DVector=packed record
X,Y: double;
end;
 
 
type T2DPolygon = array of T2DVector;
 
 
function VectorSubtract2D(const V1,V2: T2DVector): T2DVector;
{Subtract V2 from V1}
begin
Result.X:= V1.X - V2.X;
Result.Y:= V1.Y - V2.Y;
end;
 
 
 
function ScalarProduct2D(const V: T2DVector; const S: double): T2DVector;
{Multiply vector by scalar}
begin
Result.X:=V.X * S;
Result.Y:=V.Y * S;
end;
 
 
function VectorAdd2D(const V1,V2: T2DVector): T2DVector;
{Add V1 and V2}
begin
Result.X:= V1.X + V2.X;
Result.Y:= V1.Y + V2.Y;
end;
 
 
 
function ScalarDivide2D(const V: T2DVector; const S: double): T2DVector;
{Divide vector by scalar}
begin
Result.X:=V.X / S;
Result.Y:=V.Y / S;
end;
 
{---------------- Recursive Bezier Quadratic Spline ---------------------------}
 
function IsZero(const A: double): Boolean;
const Epsilon = 1E-15 * 1000;
begin
Result := Abs(A) <= Epsilon;
end;
 
 
function GetEndPointTangent(EndPnt, Adj: T2DVector; tension: double): T2DVector;
{ Calculates Bezier points from cardinal spline endpoints.}
begin
{ tangent at endpoints is the line from the endpoint to the adjacent point}
Result:=VectorAdd2D(ScalarProduct2D(VectorSubtract2D(Adj, EndPnt), tension), EndPnt);
end;
 
 
 
procedure GetInteriorTangent(const pts: T2DPolygon; Tension: double; var P1,P2: T2DVector);
{ Calculate incoming and outgoing tangents.}
{Pts[0] = Previous point, Pts[1] = Current Point, Pts[2] = Next Point}
var Diff,TV: T2DVector;
begin
{ Tangent Vector = Next Point - Previous Point * Tension}
Diff:=VectorSubtract2D(pts[2],pts[0]);
TV:=ScalarProduct2D(Diff,Tension);
 
{ Add/Subtract tangent vector to get control points}
P1:=VectorSubtract2D(pts[1],TV);
P2:=VectorAdd2D(pts[1],TV);
end;
 
 
function VectorMidPoint(const P1,P2: T2DVector): T2DVector;
begin
Result:=ScalarDivide2D(VectorAdd2D(P1,P2),2);
end;
 
 
{Don't change item order}
 
type TBezierPoints = packed record
BeginPoint,BeginControl,
EndControl,EndPoint: T2DVector;
end;
 
 
function ControlBetweenBeginEnd(BeginPoint,BeginControl,EndControl,EndPoint: double): boolean;
{ Are control points are between begin and end point}
begin
Result:=False;
if BeginControl < BeginPoint then
begin
if BeginControl < EndPoint then exit;
end
else if BeginControl > EndPoint then exit;
 
if EndControl < BeginPoint then
begin
if EndControl < EndPoint then exit;
end
else if EndControl > EndPoint then exit;
Result:=True;
end;
 
 
function RecursionDone(const Points: TBezierPoints): Boolean;
{ Function to check that recursion can be terminated}
{ Returns true if the recusion can be terminated }
const BezierPixel = 1;
var dx, dy: double;
begin
dx := Points.EndPoint.x - Points.BeginPoint.x;
dy := Points.EndPoint.y - Points.BeginPoint.y;
if Abs(dy) <= Abs(dx) then
begin
{ shallow line - check that control points are between begin and end}
Result:=False;
if not ControlBetweenBeginEnd(Points.BeginPoint.X,Points.BeginControl.X,Points.EndControl.X,Points.EndPoint.X) then exit;
 
Result:=True;
if IsZero(dx) then exit;
 
if (Abs(Points.BeginControl.y - Points.BeginPoint.y - (dy / dx) * (Points.BeginControl.x - Points.BeginPoint.x)) > BezierPixel) or
(Abs(Points.EndControl.y - Points.BeginPoint.y - (dy / dx) * (Points.EndControl.x - Points.BeginPoint.x)) > BezierPixel) then
begin
Result := False;
exit;
end
else
begin
Result := True;
exit;
end;
end
else
begin
{ steep line - check that control points are between begin and end}
Result:=False;
if not ControlBetweenBeginEnd(Points.BeginPoint.Y,Points.BeginControl.Y,Points.EndControl.Y,Points.EndPoint.Y) then exit;
Result:=True;
if IsZero(dy) then exit;
 
if (Abs(Points.BeginControl.x - Points.BeginPoint.x - (dx / dy) * (Points.BeginControl.y - Points.BeginPoint.y)) > BezierPixel) or
(Abs(Points.EndControl.x - Points.BeginPoint.x - (dx / dy) * (Points.EndControl.y - Points.BeginPoint.y)) > BezierPixel) then
begin
Result := False;
exit;
end
else
begin
Result := True;
exit;
end;
end;
end;
 
 
 
procedure BezierRecursion(var Points: TBezierPoints; var PtsOut: T2DPolygon; var Alloc, OutCount: Integer; level: Integer);
{Recursively subdivide the space between the two Bezier end-points}
var Points2: TBezierPoints; { for the second recursive call}
begin
{Out of memory?}
if OutCount = Alloc then
begin
{then double hte memory allocation}
Alloc := Alloc * 2;
SetLength(PtsOut, Alloc);
end;
 
if (level = 0) or RecursionDone(Points) then { Recursion can be terminated}
begin
if OutCount = 0 then
begin
PtsOut[0] := Points.BeginPoint;
OutCount := 1;
end;
PtsOut[OutCount] := Points.EndPoint;
Inc(OutCount);
end
else
begin
{Split Points into two halves}
Points2.EndPoint:=Points.EndPoint;
Points2.EndControl:=VectorMidPoint(Points.EndControl, Points.EndPoint);
Points2.BeginPoint:=VectorMidPoint(Points.BeginControl, Points.EndControl);
Points2.BeginControl:=VectorMidPoint(Points2.BeginPoint,Points2.EndControl);
 
Points.BeginControl:=VectorMidPoint(Points.BeginPoint, Points.BeginControl);
Points.EndControl:=VectorMidPoint(Points.BeginControl, Points2.BeginPoint);
Points.EndPoint:=VectorMidPoint(Points.EndControl, Points2.BeginControl);
 
Points2.BeginPoint := Points.EndPoint;
 
{ Do recursion on the two halves}
BezierRecursion(Points, PtsOut, Alloc, OutCount, level - 1);
BezierRecursion(Points2, PtsOut, Alloc, OutCount, level - 1);
end;
end;
 
 
procedure DoQuadraticBezier(const Source: T2DPolygon; var Destination: T2DPolygon);
{Generate Bezier spline from Source polygon and store result in Destination }
{Source Format: P[0] = Start Point, P[1]= Control Point, P[2] = End Point }
var B, Alloc,OutCount: Integer;
var ptBuf: TBezierPoints;
begin
if (Length(Source) - 1) mod 3 <> 0 then exit;
OutCount := 0;
{Start with allocation of 150 to save allocation overhead}
Alloc := 150;
SetLength(Destination, Alloc);
for B:=0 to (Length(Source) - 1) div 3 - 1 do
begin
Move(Source[B * 3], ptBuf.BeginPoint, SizeOf(ptBuf));
BezierRecursion(ptBuf, Destination, Alloc, OutCount, 8);
end;
{Trim Destination to actual length}
SetLength(Destination,OutCount);
end;
 
 
 
procedure GetCardinalSpline(const Source: T2DPolygon; var Destination: T2DPolygon; Tension: double = 0.5);
{Generate cardinal spline from Source with result in Destination}
{Generate tangents to get the Cardinal Spline}
var i: Integer;
var pt: T2DPolygon;
var P1,P2: T2DVector;
begin
{We need at least 2 points}
if Length(Source) <= 1 then exit;
 
{ The points and tangents require count * 3 - 2 points.}
SetLength(pt, Length(Source) * 3 - 2);
tension := tension * 0.3;
 
{Calculate Tangents for each point and store results in new array}
 
{Do the first point}
pt[0]:=Source[0];
pt[1]:=GetEndPointTangent(Source[0], Source[1], tension);
 
{Do intermediates points}
for i := 0 to Length(Source) - 3 do
begin
GetInteriorTangent(T2DPolygon(@(Source[i])), tension, P1,P2);
pt[3 * i + 2]:=P1;
pt[3 * i + 3]:=Source[i + 1];
pt[3 * i + 4]:=P2;
end;
{Do last point}
pt[Length(Pt) - 1]:=Source[Length(Source) - 1];
pt[Length(Pt) - 2]:=GetEndPointTangent(Source[Length(Source) - 1], Source[Length(Source) - 2], Tension);
 
DoQuadraticBezier(pt, Destination);
end;
 
 
procedure DrawPolyline(Image: TImage; const Points: T2DPolygon);
{Draw specified polygon}
var I: Integer;
begin
if Length(Points) <2 then exit;
Image.Canvas.MoveTo(Trunc(points[0].X), Trunc(points[0].Y));
for I := 1 to Length(Points) - 1 do
begin
Image.Canvas.LineTo(Trunc(points[I].X), Trunc(points[I].Y));
end;
end;
 
 
procedure DrawCurve(Image: TImage; const Points: T2DPolygon; Tension: double = 0.5);
{Draw control points and resulting spline curve }
var Pt2: T2DPolygon;
begin
if Length(Points) <= 1 then exit;
GetCardinalSpline(points, Pt2, tension);
{Draw control points}
Image.Canvas.Pen.Width:=2;
Image.Canvas.Pen.Color:=clBlue;
DrawPolyline(Image,Points);
{Draw actual spline curve}
Image.Canvas.Pen.Color:=clRed;
DrawPolyline(Image,Pt2);
end;
 
 
procedure ShowQuadBezierCurve(Image: TImage);
var Points: T2DPolygon;
begin
{Create a set of control points}
SetLength(Points,5);
Points[0].X:=50; Points[0].Y:=250;
Points[1].X:=50; Points[1].Y:=50;
Points[2].X:=250; Points[2].Y:=50;
Points[3].X:=350; Points[3].Y:=150;
Points[4].X:=400; Points[4].Y:=100;
DrawCurve(Image, Points);
Image.Invalidate;
end;
 
 
</syntaxhighlight>
{{out}}
<pre>
Elapsed Time: 0.647 ms.
</pre>
 
=={{header|Factor}}==
Some code is shared with the cubic bezier task, but I put it here again to make it simple (hoping the two version don't diverge)
Same remark as with cubic bezier, the points could go into a sequence to simplify stack shuffling
<syntaxhighlight lang="factor">USING: arrays kernel locals math math.functions
rosettacode.raster.storage sequences ;
IN: rosettacode.raster.line
 
! This gives a function
:: (quadratic-bezier) ( P0 P1 P2 -- bezier )
[ :> x
1 x - sq P0 n*v
2 1 x - x * * P1 n*v
x sq P2 n*v
v+ v+ ] ; inline
 
! Same code from the cubic bezier task
: t-interval ( x -- interval )
[ iota ] keep 1 - [ / ] curry map ;
: 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 image -- )
100 t-interval P0 P1 P2 (quadratic-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 287 ⟶ 818:
WEND
END SUB
END SUB</langsyntaxhighlight>
'''Output:''' [[File:FBSLBezierQuad.PNG]]
 
=={{header|Factor}}==
Some code is shared with the cubic bezier task, but I put it here again to make it simple (hoping the two version don't diverge)
Same remark as with cubic bezier, the points could go into a sequence to simplify stack shuffling
<lang factor>USING: arrays kernel locals math math.functions
rosettacode.raster.storage sequences ;
IN: rosettacode.raster.line
 
! This gives a function
:: (quadratic-bezier) ( P0 P1 P2 -- bezier )
[ :> x
1 x - sq P0 n*v
2 1 x - x * * P1 n*v
x sq P2 n*v
v+ v+ ] ; inline
 
! Same code from the cubic bezier task
: t-interval ( x -- interval )
[ iota ] keep 1 - [ / ] curry map ;
: 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 image -- )
100 t-interval P0 P1 P2 (quadratic-bezier) map
points-to-lines
{R,G,B} swap image draw-lines ;
</lang>
 
=={{header|Fortran}}==
{{works with|Fortran|90 and later}}
Line 323 ⟶ 825:
(This subroutine must be inside the <code>RCImagePrimitive</code> module, see [[Bresenham's line algorithm#Fortran|here]])
 
<langsyntaxhighlight lang="fortran">subroutine quad_bezier(img, p1, p2, p3, color)
type(rgbimage), intent(inout) :: img
type(point), intent(in) :: p1, p2, p3
Line 348 ⟶ 850:
end do
 
end subroutine quad_bezier</langsyntaxhighlight>
=={{header|FreeBASIC}}==
{{trans|BBC BASIC}}
<langsyntaxhighlight lang="freebasic">' version 01-11-2016
' compile with: fbc -s console
 
Line 413 ⟶ 915:
Print : Print "hit any key to end program"
Sleep
End</langsyntaxhighlight>
 
 
=={{header|FutureBasic}}==
FB has a convenience quadratic Bézier curve function that accepts a start point, end point, left control point, right control point, path stroke width and path color as demonstrated below. Here's a link to an illustration that's helpful in understanding the inputs:
[https://i.stack.imgur.com/WLZ5o.png Bézier curve function paramters.]
<syntaxhighlight lang="futurebasic">
_window = 1
 
void local fn BuildWindow
window _window, @"Quadratic Bezier Curve", ( 0, 0, 300, 300 ), NSWindowStyleMaskTitled + NSWindowStyleMaskClosable + NSWindowStyleMaskMiniaturizable
WindowCenter(1)
WindowSubclassContentView( _window )
ViewSetFlipped( _windowContentViewTag, YES )
ViewSetNeedsDisplay( _windowContentViewTag )
end fn
 
void local fn DrawInView( tag as long )
BezierPathStrokeCurve( fn CGPointMake( 20, 20 ), fn CGPointMake( 280, 20 ), fn CGPointMake( 60, 340 ), fn CGPointMake( 240, 340 ), 4.0, fn ColorRed )
end fn
 
void local fn DoDialog( ev as long, tag as long )
select ( ev )
case _viewDrawRect : fn DrawInView( tag )
case _windowWillClose : end
end select
end fn
 
on dialog fn DoDialog
 
fn BuildWindow
 
HandleEvents
</syntaxhighlight>
{{output}}
[[File:Quadratic Bezier Curve.png]]
 
=={{header|Go}}==
{{trans|C}}
<langsyntaxhighlight lang="go">package raster
 
const b2Seg = 20
Line 443 ⟶ 980:
func (b *Bitmap) Bézier2Rgb(x1, y1, x2, y2, x3, y3 int, c Rgb) {
b.Bézier2(x1, y1, x2, y2, x3, y3, c.Pixel())
}</langsyntaxhighlight>
Demonstration program:
[[File:GoBez2.png|thumb|right]]
<langsyntaxhighlight lang="go">package main
 
import (
Line 460 ⟶ 997:
fmt.Println(err)
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">{-# LANGUAGE
FlexibleInstances, TypeSynonymInstances,
ViewPatterns #-}
Line 509 ⟶ 1,046:
pt n p = pmap (*n) p
f (curvePoint -> p1) (curvePoint -> p2) =
line i (toPixel p1) (toPixel p2) c</langsyntaxhighlight>
 
=={{header|J}}==
See [[Cubic bezier curves#J|Cubic bezier curves]] for a generalized solution.=={{header|J}}==
 
=={{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 BezierQuadratic {
 
public static void main(String[] args) throws IOException {
final int width = 320;
final int height = 320;
BasicBitmapStorage bitmap = new BasicBitmapStorage(width, height);
bitmap.fill(Color.YELLOW);
Point point1 = new Point(10, 100);
Point point2 = new Point(250, 270);
Point point3 = new Point(150, 20);
bitmap.quadraticBezier(point1, point2, point3, Color.BLACK, 20);
File bezierFile = new File("QuadraticBezierJava.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 quadraticBezier(Point point1, Point point2, Point point3, 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;
final double b = 2.0 * t * u;
final double c = t * t;
final int x = (int) ( a * point1.x + b * point2.x + c * point3.x );
final int y = (int) ( a * point1.y + b * point2.y + c * point3.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:QuadraticBezierJava.jpg]]
 
=={{header|Julia}}==
See [[Cubic bezier curves#Julia]] for a generalized solution.
=={{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 quadraticBezier(p1: Point, p2: Point, p3: 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
val b = 2.0 * t * u
val c = t * t
pts[i].x = (a * p1.x + b * p2.x + c * p3.x).toInt()
pts[i].y = (a * p1.y + b * p2.y + c * p3.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 = 320
val height = 320
val bbs = BasicBitmapStorage(width, height)
with (bbs) {
fill(Color.cyan)
val p1 = Point(10, 100)
val p2 = Point(250, 270)
val p3 = Point(150, 20)
quadraticBezier(p1, p2, p3, Color.black, 20)
val qbFile = File("quadratic_bezier.jpg")
ImageIO.write(image, "jpg", qbFile)
}
}</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.quadraticbezier = function(self, x1, y1, x2, y2, x3, y3, nseg)
nseg = nseg or 10
local prevx, prevy, currx, curry
for i = 0, nseg do
local t = i / nseg
local a, b, c = (1-t)^2, 2*t*(1-t), t^2
prevx, prevy = currx, curry
currx = math.floor(a * x1 + b * x2 + c * x3 + 0.5)
curry = math.floor(a * y1 + b * y2 + c * y3 + 0.5)
if i > 0 then
self:line(prevx, prevy, currx, curry)
end
end
end
local bitmap = Bitmap(61,21)
bitmap:clear()
bitmap:quadraticbezier( 1,1, 30,37, 59,1 )
bitmap:render({[0x000000]='.', [0xFFFFFFFF]='X'})</syntaxhighlight>
{{out}}
<pre>.............................................................
.X.........................................................X.
..X.......................................................X..
...X.....................................................X...
....X...................................................X....
.....X.................................................X.....
......X...............................................X......
.......X.............................................X.......
........X...........................................X........
.........X.........................................X.........
..........X.......................................X..........
...........X.....................................X...........
............X...................................X............
.............X................................XX.............
..............X.............................XX...............
...............XX..........................X.................
.................XX.....................XXX..................
...................XXX...............XXX.....................
......................XXXXX......XXXX........................
...........................XXXXXX............................
.............................................................</pre>
=={{header|Mathematica}} / {{header|Wolfram Language}}==
<langsyntaxhighlight Mathematicalang="mathematica">pts = {{0, 0}, {1, -1}, {2, 1}};
Graphics[{BSplineCurve[pts], Green, Line[pts], Red, Point[pts]}]</langsyntaxhighlight>
Second solution using built-in function BezierCurve.
<syntaxhighlight lang="mathematica">pts = {{0, 0}, {1, -1}, {2, 1}};
Graphics[{BezierCurve[pts], Green, Line[pts], Red, Point[pts]}]</syntaxhighlight>
[[File:MmaQuadraticBezier.png]]
 
=={{header|MATLAB}}==
Note: Store this function in a file named "bezierQuad.mat" in the @Bitmap folder for the Bitmap class defined [[Bitmap#MATLAB|here]].
<syntaxhighlight lang="matlab">
<lang MATLAB>
function bezierQuad(obj,pixel_0,pixel_1,pixel_2,color,varargin)
 
Line 554 ⟶ 1,324:
end
</syntaxhighlight>
</lang>
 
Sample usage:
This will generate the image example for the Go solution.
<syntaxhighlight lang="matlab">
<lang MATLAB>
>> img = Bitmap(400,300);
>> img.fill([223 255 239]);
>> img.bezierQuad([20 150],[500 -100],[300 280],[63 143 239],21);
>> 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
 
quadraticBezier = function(img, p1, p2, p3, numPoints, colr)
points = []
for i in range(0, numPoints)
t = i / numPoints
u = 1 - t
a = u * u
b = 2 * t * u
c = t * t
x = floor(a * p1.x + b * p2.x + c * p3.x)
y = floor(a * p1.y + b * p2.y + c * p3.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, 55)
 
quadraticBezier bezier, p1, p2, p3, 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 drawQuadraticBezier*(
image: Image; pt1, pt2, pt3: Point; color: Color; nseg: Positive = 20) =
 
var points = newSeq[Point](nseg + 1)
 
for i in 0..nseg:
let t = i / nseg
let a = (1 - t) * (1 - t)
let b = 2 * t * (1 - t)
let c = t * t
 
points[i] = (x: (a * pt1.x + b * pt2.x + c * pt3.x).toInt,
y: (a * pt1.y + b * pt2.y + c * pt3.y).toInt)
 
for i in 1..points.high:
image.drawLine(points[i - 1], points[i], color)
 
#———————————————————————————————————————————————————————————————————————————————————————————————————
 
when isMainModule:
var img = newImage(16, 12)
img.fill(White)
img.drawQuadraticBezier((1, 7), (7, 12), (14, 1), Black)
img.print</syntaxhighlight>
 
{{out}}
<pre>................
..............H.
.............H..
.............H..
............H...
...........H....
..........HH....
.HH......H......
..HH..HHH.......
....HH..........
................
................</pre>
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">let quad_bezier ~img ~color
~p1:(_x1, _y1)
~p2:(_x2, _y2)
Line 606 ⟶ 1,494:
in
by_pair pts (fun p0 p1 -> line ~p0 ~p1);
;;</langsyntaxhighlight>
=={{header|Phix}}==
Output similar to [[Bitmap/Bézier_curves/Quadratic#Mathematica|Mathematica]]<br>
Requires new_image() from [[Bitmap#Phix|Bitmap]], bresLine() from [[Bitmap/Bresenham's_line_algorithm#Phix|Bresenham's_line_algorithm]], and 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_BezierQuadratic.exw
include ppm.e -- black, green, red, white, new_image(), write_ppm(), bresLine() -- (covers above requirements)
 
function quadratic_bezier(sequence img, atom x1, y1, x2, y2, x3, y3, integer colour, segments)
=={{header|Perl 6}}==
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,2),
b = 2*t*t1,
c = power(t,2)
pts[i+1] = floor(a*x1+b*x2+c*x3)
pts[i+2] = floor(a*y1+b*y2+c*y3)
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(200,200,black)
img = quadratic_bezier(img, 0,100, 100,200, 200,0, white, 40)
img = bresLine(img,0,100,100,200,green)
img = bresLine(img,100,200,200,0,green)
img[1][100] = red
img[100][200] = red
img[200][1] = red
write_ppm("BezierQ.ppm",img)</syntaxhighlight>
=={{header|PicoLisp}}==
This uses the 'brez' line drawing function from
[[Bitmap/Bresenham's line algorithm#PicoLisp]].
<syntaxhighlight lang="picolisp">(scl 6)
 
(de quadBezier (Img N X1 Y1 X2 Y2 X3 Y3)
(let (R (* N N) X X1 Y Y1 DX 0 DY 0)
(for I N
(let (J (- N I) A (*/ 1.0 J J R) B (*/ 2.0 I J R) C (*/ 1.0 I I R))
(brez Img X Y
(setq DX (- (+ (*/ A X1 1.0) (*/ B X2 1.0) (*/ C X3 1.0)) X))
(setq DY (- (+ (*/ A Y1 1.0) (*/ B Y2 1.0) (*/ C Y3 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
(quadBezier Img 12 20 100 300 -80 260 180)
(out "img.pbm" # Write to bitmap file
(prinl "P1")
(prinl 300 " " 200)
(mapc prinl Img) ) )
 
(call 'display "img.pbm")</syntaxhighlight>
=={{header|PureBasic}}==
<syntaxhighlight lang="purebasic">Procedure quad_bezier(img, p1x, p1y, p2x, p2y, p3x, p3y, 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, 2)
b = 2.0 * T * t1
c = Pow(T, 2)
pts(i)\x = a * p1x + b * p2x + c * p3x
pts(i)\y = a * p1y + b * p2y + c * p3y
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)
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, quadratic", #PB_Window_SystemMenu)
quad_bezier(1, 80,20, 130,80, 20,150, 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}}==
See [[Cubic bezier curves#Python]] for a generalized solution.
=={{header|R}}==
See [[Cubic bezier curves#R]] for a generalized solution.
=={{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)
(for/list ([t (in-range 0.0 1.0 (/ 1.0 20))])
(int t (int t p0 p1) (int t p1 p2))))
 
(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)))
bm
</syntaxhighlight>
=={{header|Raku}}==
(formerly Perl 6)
{{works with|Rakudo|2017.09}}
Uses pieces from [[Bitmap#Perl_6Raku| Bitmap]], and [[Bitmap/Bresenham's_line_algorithm#Perl_6Raku| Bresenham's line algorithm]] tasks. They are included here to make a complete, runnable program.
 
<syntaxhighlight lang="raku" perl6line>class Pixel { has UInt ($.R, $.G, $.B) }
class Bitmap {
has UInt ($.width, $.height);
Line 710 ⟶ 1,723:
@points.map: { $b.dot( $_, color(255,0,0), 3 )}
 
$*OUT.write: $b.P6;</langsyntaxhighlight>
 
See [https://github.com/thundergnat/rc/blob/master/img/Bezier-quadratic-perl6.png example image here], (converted to a .png as .ppm format is not widely supported).
 
=={{header|Phix}}==
Output similar to [[Bitmap/Bézier_curves/Quadratic#Mathematica|Mathematica]]
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]].
Included as demo\rosetta\Bitmap_BezierQuadratic.exw, results may be verified with demo\rosetta\viewppm.exw
<lang Phix>function quadratic_bezier(sequence img, atom x1, atom y1, atom x2, atom y2, atom x3, atom y3, integer colour, integer segments)
atom t, t1, a, b, c
sequence pts = repeat(0,segments*2)
 
for i=0 to segments*2-1 by 2 do
t = i/segments
t1 = 1-t
a = power(t1,2)
b = 2*t*t1
c = power(t,2)
pts[i+1] = floor(a*x1+b*x2+c*x3)
pts[i+2] = floor(a*y1+b*y2+c*y3)
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(200,200,black)
img = quadratic_bezier(img, 0,100, 100,200, 200,0, white, 40)
img = bresLine(img,0,100,100,200,green)
img = bresLine(img,100,200,200,0,green)
img[1][100] = red
img[100][200] = red
img[200][1] = red
write_ppm("BézierQ.ppm",img)</lang>
 
=={{header|PicoLisp}}==
This uses the 'brez' line drawing function from
[[Bitmap/Bresenham's line algorithm#PicoLisp]].
<lang PicoLisp>(scl 6)
 
(de quadBezier (Img N X1 Y1 X2 Y2 X3 Y3)
(let (R (* N N) X X1 Y Y1 DX 0 DY 0)
(for I N
(let (J (- N I) A (*/ 1.0 J J R) B (*/ 2.0 I J R) C (*/ 1.0 I I R))
(brez Img X Y
(setq DX (- (+ (*/ A X1 1.0) (*/ B X2 1.0) (*/ C X3 1.0)) X))
(setq DY (- (+ (*/ A Y1 1.0) (*/ B Y2 1.0) (*/ C Y3 1.0)) Y)) )
(inc 'X DX)
(inc 'Y DY) ) ) ) )</lang>
Test:
<lang PicoLisp>(let Img (make (do 200 (link (need 300 0)))) # Create image 300 x 200
(quadBezier Img 12 20 100 300 -80 260 180)
(out "img.pbm" # Write to bitmap file
(prinl "P1")
(prinl 300 " " 200)
(mapc prinl Img) ) )
 
(call 'display "img.pbm")</lang>
 
=={{header|PureBasic}}==
<lang PureBasic>Procedure quad_bezier(img, p1x, p1y, p2x, p2y, p3x, p3y, 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, 2)
b = 2.0 * T * t1
c = Pow(T, 2)
pts(i)\x = a * p1x + b * p2x + c * p3x
pts(i)\y = a * p1y + b * p2y + c * p3y
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)
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, quadratic", #PB_Window_SystemMenu)
quad_bezier(1, 80,20, 130,80, 20,150, RGB(255, 255, 255), 20)
ImageGadget(0, 0, 0, w, h, ImageID(1))
 
Define event
Repeat
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
</lang>
 
=={{header|Python}}==
See [[Cubic bezier curves#Python]] for a generalized solution.
 
=={{header|R}}==
See [[Cubic bezier curves#R]] for a generalized solution.
 
=={{header|Racket}}==
<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)
(for/list ([t (in-range 0.0 1.0 (/ 1.0 20))])
(int t (int t p0 p1) (int t p1 p2))))
 
(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)))
bm
</lang>
 
=={{header|Ruby}}==
See [[Cubic bezier curves#Ruby]] for a generalized solution.
 
=={{header|Tcl}}==
See [[Cubic bezier curves#Tcl]] for a generalized solution.
 
=={{header|TI-89 BASIC}}==
 
{{TI-image-task}}
 
<langsyntaxhighlight lang="ti89b">Define cubic(p1,p2,p3,segs) = Prgm
Local i,t,u,prev,pt
0 → pt
Line 866 ⟶ 1,746:
EndIf
EndFor
EndPrgm</langsyntaxhighlight>
 
=={{header|Vedit macro language}}==
This implementation uses de Casteljau's algorithm to recursively split the Bezier curve into two smaller segments until the segment is short enough to be approximated with a straight line.
Line 874 ⟶ 1,753:
Constant recursion depth is used here. Recursion depth of 5 seems to give accurate enough result in most situations. In real world implementations, some adaptive method is often used to decide when to stop recursion.
 
<langsyntaxhighlight lang="vedit">// Daw a Cubic bezier curve
// #20, #30 = Start point
// #21, #31 = Control point 1
Line 906 ⟶ 1,785:
Call("DRAW_LINE")
}
return</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 bmpQuadraticBezier(name, p1, p2, p3, 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
var b = 2 * t * u
var c = t * t
var px = (a * p1.x + b * p2.x + c * p3.x).truncate
var py = (a * p1.y + b * p2.y + c * p3.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 = "Quadratic Bézier curve"
var size = 320
Window.resize(size, size)
Canvas.resize(size, size)
var name = "quadratic"
var bmp = bmpCreate(name, size, size)
bmpFill(name, Color.white)
var p1 = Point.new( 10, 100)
var p2 = Point.new(250, 270)
var p3 = Point.new(150, 20)
bmpQuadraticBezier(name, p1, p2, p3, Color.darkpurple, 20)
bmp.draw(0, 0)
}
 
static update() {}
 
static draw(alpha) {}
}</syntaxhighlight>
 
=={{header|XPL0}}==
[[File:QuadXPL0.png|right]]
<langsyntaxhighlight XPL0lang="xpl0">include c:\cxpl\codes; \intrinsic 'code' declarations
 
proc Bezier(P0, P1, P2); \Draw quadratic Bezier curve
Line 935 ⟶ 1,893:
if ChIn(1) then []; \wait for keystroke
SetVid(3); \restore normal text display
]</langsyntaxhighlight>
 
=={{header|zkl}}==
Uses the PPM class from http://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#zkl
 
Add this to the PPM class:
<langsyntaxhighlight lang="zkl"> fcn qBezier(p0x,p0y, p1x,p1y, p2x,p2y, rgb, numPts=500){
numPts.pump(Void,'wrap(t){ // B(t)
t=t.toFloat()/numPts; t1:=(1.0 - t);
Line 949 ⟶ 1,906:
__sSet(rgb,x,y);
});
}</langsyntaxhighlight>
Doesn't use line segments, they don't seem like an improvement.
<langsyntaxhighlight lang="zkl">bitmap:=PPM(200,200,0xff|ff|ff);
bitmap.qBezier(10,100, 250,270, 150,20, 0);
bitmap.write(File("foo.ppm","wb"));</langsyntaxhighlight>
{{out}}
Same as the BBC BASIC image:[[Image:bezierquad_bbc.gif]]
 
{{omit from|AWK}}
{{omit from|GUISS}}
Anonymous user