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

(→‎{{header|Lua}}: added Lua solution)
imported>Chinhouse
 
(13 intermediate revisions by 7 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}}
<langsyntaxhighlight Actionlang="action!">INCLUDE "H6:RGBLINE.ACT" ;from task Bresenham's line algorithm
INCLUDE "H6:REALMATH.ACT"
 
Line 119 ⟶ 118:
DO UNTIL CH#$FF OD
CH=$FF
RETURN</langsyntaxhighlight>
{{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 146 ⟶ 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 172 ⟶ 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 226:
GCOL 1
LINE x%*2,y%*2,x%*2,y%*2
ENDPROC</langsyntaxhighlight>
 
=={{header|C}}==
Line 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 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 292:
}
#undef plot
#undef line</langsyntaxhighlight>
 
 
 
=={{header|Commodore Basic}}==
<langsyntaxhighlight lang="basic">
10 rem bezier curve algorihm
20 rem translated from purebasic
Line 352 ⟶ 354:
3160 next i
3170 return
</syntaxhighlight>
</lang>
[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 385 ⟶ 386:
im.quadraticBezier(Pt(1,10), Pt(25,27), Pt(15,2), Gray.black);
im.textualShow();
}</langsyntaxhighlight>
{{out}}
<pre>....................
Line 407 ⟶ 408:
....................
....................</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
<langsyntaxhighlight lang="factor">USING: arrays kernel locals math math.functions
rosettacode.raster.storage sequences ;
IN: rosettacode.raster.line
Line 434 ⟶ 758:
points-to-lines
{R,G,B} swap image draw-lines ;
</syntaxhighlight>
</lang>
 
=={{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 495 ⟶ 818:
WEND
END SUB
END SUB</langsyntaxhighlight>
'''Output:''' [[File:FBSLBezierQuad.PNG]]
 
=={{header|Fortran}}==
{{works with|Fortran|90 and later}}
Line 503 ⟶ 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 528 ⟶ 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 594 ⟶ 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 624 ⟶ 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 641 ⟶ 997:
fmt.Println(err)
}
}</langsyntaxhighlight>
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">{-# LANGUAGE
FlexibleInstances, TypeSynonymInstances,
ViewPatterns #-}
Line 690 ⟶ 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.
<langsyntaxhighlight lang="scala">// Version 1.2.40
 
import java.awt.Color
Line 774 ⟶ 1,241:
ImageIO.write(image, "jpg", qbFile)
}
}</langsyntaxhighlight>
=={{header|Lua}}==
Starting with the code from [[Bitmap/Bresenham's line algorithm#Lua|Bitmap/Bresenham's line algorithm]], then extending:
<langsyntaxhighlight lang="lua">Bitmap.quadraticbezier = function(self, x1, y1, x2, y2, x3, y3, nseg)
nseg = nseg or 10
local prevx, prevy, currx, curry
Line 795 ⟶ 1,262:
bitmap:clear()
bitmap:quadraticbezier( 1,1, 30,37, 59,1 )
bitmap:render({[0x000000]='.', [0xFFFFFFFF]='X'})</langsyntaxhighlight>
{{out}}
<pre>.............................................................
Line 818 ⟶ 1,285:
...........................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.
<langsyntaxhighlight Mathematicalang="mathematica">pts = {{0, 0}, {1, -1}, {2, 1}};
Graphics[{BezierCurve[pts], Green, Line[pts], Red, Point[pts]}]</langsyntaxhighlight>
[[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 859 ⟶ 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.
<langsyntaxhighlight Nimlang="nim">import bitmap
import bresenham
import lenientops
Line 900 ⟶ 1,439:
img.fill(White)
img.drawQuadraticBezier((1, 7), (7, 12), (14, 1), Black)
img.print</langsyntaxhighlight>
 
{{out}}
Line 915 ⟶ 1,454:
................
................</pre>
 
=={{header|OCaml}}==
 
<langsyntaxhighlight lang="ocaml">let quad_bezier ~img ~color
~p1:(_x1, _y1)
~p2:(_x2, _y2)
Line 956 ⟶ 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
<langsyntaxhighlight Phixlang="phix">-- demo\rosetta\Bitmap_BezierQuadratic.exw
include ppm.e -- black, green, red, white, new_image(), write_ppm(), bresLine() -- (covers above requirements)
 
Line 989 ⟶ 1,526:
img[100][200] = red
img[200][1] = red
write_ppm("BezierQ.ppm",img)</langsyntaxhighlight>
 
=={{header|PicoLisp}}==
This uses the 'brez' line drawing function from
[[Bitmap/Bresenham's line algorithm#PicoLisp]].
<langsyntaxhighlight PicoLisplang="picolisp">(scl 6)
 
(de quadBezier (Img N X1 Y1 X2 Y2 X3 Y3)
Line 1,004 ⟶ 1,540:
(setq DY (- (+ (*/ A Y1 1.0) (*/ B Y2 1.0) (*/ C Y3 1.0)) Y)) )
(inc 'X DX)
(inc 'Y DY) ) ) ) )</langsyntaxhighlight>
Test:
<langsyntaxhighlight PicoLisplang="picolisp">(let Img (make (do 200 (link (need 300 0)))) # Create image 300 x 200
(quadBezier Img 12 20 100 300 -80 260 180)
(out "img.pbm" # Write to bitmap file
Line 1,013 ⟶ 1,549:
(mapc prinl Img) ) )
 
(call 'display "img.pbm")</langsyntaxhighlight>
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">Procedure quad_bezier(img, p1x, p1y, p2x, p2y, p3x, p3y, Color, n_seg)
Protected i
Protected.f T, t1, a, b, c, d
Line 1,051 ⟶ 1,586:
event = WaitWindowEvent()
Until event = #PB_Event_CloseWindow
</syntaxhighlight>
</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}}==
<langsyntaxhighlight lang="racket">
#lang racket
(require racket/draw)
Line 1,087 ⟶ 1,619:
(draw-lines dc (bezier-points '(16 1) '(1 4) '(3 16)))
bm
</syntaxhighlight>
</lang>
 
=={{header|Raku}}==
(formerly Perl 6)
Line 1,094 ⟶ 1,625:
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" perl6line>class Pixel { has UInt ($.R, $.G, $.B) }
class Bitmap {
has UInt ($.width, $.height);
Line 1,192 ⟶ 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|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 1,218 ⟶ 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 1,226 ⟶ 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 1,258 ⟶ 1,785:
Call("DRAW_LINE")
}
return</langsyntaxhighlight>
 
=={{header|Wren}}==
{{libheader|DOME}}
Requires version 1.3.0 of DOME or later.
<langsyntaxhighlight ecmascriptlang="wren">import "graphics" for Canvas, ImageData, Color, Point
import "dome" for Window
 
Line 1,337 ⟶ 1,863:
 
static draw(alpha) {}
}</langsyntaxhighlight>
 
=={{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 1,367 ⟶ 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 1,381 ⟶ 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