#!/usr/bin/perl # exercise Content.pm's bspline call as much as possible # outputs Bspline.pdf # author: Phil M Perry # notes on display: # # -debug settings: 0 = only black line of final Bezier spline (default) # 1 = draw filled green circles of given points (incl move-to) # 2 = draw thick green line of polyline between points # 3 = draw thin blue line of natural tangent at each point # 4 = draw red open circle control points if curve, with # dashed red line connecting to associated point # Note that debug drawings are fixed in Content.pm's bspline() call and # only the black line output is handled here. # # -firstseg controls display and shape of first segment (from current point) # -lastseg controls display and shape of last segment (to final point) # 'curve' = draw Bezier curve (default) # 'line2' = draw straight line between points, forcing new tangents # 'line1' = draw curve, but constrain at "end" point to be on polyline # 'constraint2' = like 'line2', but not drawn # 'constraint1' = like 'line1', but not drawn # # -ratio value > 0 as distance of a curve's control point from its associated # end point, as a fraction of the polyline distance to the next point # # -colinear # 'curve' = attempt to draw Bezier curve from or to a colinear point # 'line' = force a line segment (equals polyline segment) between adjacent # colinear points use warnings; use strict; our $VERSION = '3.021'; # VERSION my $LAST_UPDATE = '3.021'; # manually update whenever code is changed use Math::Trig; use List::Util qw(min max); #use constant in => 1 / 72; #use constant cm => 2.54 / 72; #use constant mm => 25.4 / 72; #use constant pt => 1; use PDF::Builder; my $PDFname = $0; $PDFname =~ s/\..*$//; # remove extension $PDFname .= '.pdf'; # add new extension my $globalX = 0; my $globalY = 0; my $compress = 'none'; #my $compress = 'flate'; my $pdf = PDF::Builder->new(-compress => $compress); my ($page, $grfx, $text); # objects for page, graphics, text my (@points, $i); my ($font); my @axisOffset = (5, 5); # clear the edge of the cell my $db = 4; # debug level my $pageNo = 0; # ================ pg 1 nextPage(); # next (first) page of output, 595pt wide x 792pt high my $fontR = $pdf->corefont('Times-Roman'); my $fontI = $pdf->corefont('Times-Italic'); my $fontC = $pdf->corefont('Courier'); # --------------------------------------- my ($voffset, $hoffset, @pts); $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # ================ pg 1 # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'show nothing, 1 pt total'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', '2 pt, single line segment'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'single line segment'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'straight line of 2 segments'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', '2 curves thru 3 pts'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # loop-de-loop to a single point, repeating base point @points = (10,10, 40,30, 70,60, 40,30, 60,10); _movedraw(350,600, '2.4', 'tight loop'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', '2 curves thru 3 pts'); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', '2 segments lineX forced to line1 both'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'ends 2 straight, arc between'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'S-shaped curve, ends 2 straight'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'more extreme S-shaped curve, ends 2 straight'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 4.3 but longer control lines'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', '3 curved segments'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'ends forced straight lines, center S-curve'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 5.2 but longer control lines'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', '7 straight segments in a row'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', '4 curved, center 2 nearly flat'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', '4 curved, center 2 nearly flat'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 6.2 but 3 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 6.4 but 3 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 but 4 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 but 4 nearly flat in center'); $grfx->bspline(\@pts, -debug=>$db); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 but center forced line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 but center forced line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but 2 center forced lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but 2 center forced lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line'); $grfx->stroke(); # ================ pg 2 nextPage(); # try a bunch of constraints $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'like 1-1.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', 'like 1-1.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'like 1-2.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'like 1-2.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', '2 curves that blend to straight lines due to override of constraintX by line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', 'like 2.3 as forced to line1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'like 1-4.1 but first and last segments gone and colinearity overrides constraint1 to force constraint2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'like 1-4.2 but first and last segments gone and colinearity overrides constraint1 to force constraint2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'like 1-4.3 but first and last segments gone'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 1-4.4 but first and last segments gone with longer control points making more extreme S-curve'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', 'invisible left end straight line causing curve to match, invisible right end curve matches tangent, end tangent is polyline'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'ends forced to straight lines (line2), center curve matches end lines at their tangents'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 5.2 but more extreme from longer control lines'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', 'like 1-6.1 with end segments not drawn'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', 'ends not drawn, left is line, right is curve, drawn line tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', 'ends not drawn, left is line, right is curve, drawn line tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 1-6.4 but end segments not drawn and tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 1-6.5 but end segments not drawn and tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 but new center point is flat'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 but new center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 but force center line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 but force center line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but force 2 center lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but force 2 center lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint2', -lastseg=>'constraint1'); $grfx->stroke(); # ================ pg 3 nextPage(); # try a bunch of constraints $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'like 2-1.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', 'like 2-1.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'like 2-2.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'like 2-2.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', 'like 2-2.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', 'like 2-3.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', 'like 2-3.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', 'like 2-3.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', 'like 2-3.4'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'like 2-4.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'like 2-4.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'like 2-4.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 2-4.4'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', 'end segs invisible, left curve right line, center tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'like 2-5.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 2-5.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', 'like 2-6.1, colinearity overrides constraint1 to constraint2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', 'left invisible curve, right invisible line, curve tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', 'left invisible curve, right invisible line, curve tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 6.2 but extra colinear point in middle'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 6.3 but extra colinear point in middle'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 but new flat center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 but new center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 but force center to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 but force center to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but force center 2 segments to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but force center 2 segments to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'constraint1', -lastseg=>'constraint2'); $grfx->stroke(); # ================ pg 4 nextPage(); # try a bunch of lines $grfx->strokecolor('black'); $grfx->linewidth(1); $grfx->linedash(); # @points includes first (move to) point # duplicate points removal row 1 @points = (10,10, 10,10, 10,10, 10,10); # all same point (no-op) _movedraw(30,700, '1.1', 'like 3-1.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); @points = (10,10, 10,10, 50,50, 50,50); # line segment _movedraw(100,700, '1.2', 'like 3-1.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'curve', -lastseg=>'curve'); $grfx->stroke(); # degenerate cases row 2,3 @points = (10,10, 50,50); # line segment _movedraw(30,600, '2.1', 'like 3-2.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 50,50, 90,90); # 2 colinear line segments _movedraw(100,600, '2.2', 'like 3-2.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 30,50, 90,20); # 3 points non-colinear _movedraw(200,600, '2.3', 'like 3-2.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # line2 forced to line1 since only two segments _movedraw(30,500, '3.1', 'like 3-3.1'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); # same as _movedraw(140,500, '3.2', 'like 3-3.2'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line1'); $grfx->stroke(); _movedraw(250,500, '3.3', 'like 3-3.3'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line1', -lastseg=>'line2'); $grfx->stroke(); _movedraw(360,500, '3.4', 'like 3-3.4'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # 3 colinear points beginning and end row 4 @points = (10,10, 30,30, 50,50, 90,50, 110,30, 130,10); _movedraw(30,400, '4.1', 'left line1 overridden by colinearity, right line2 line anyway'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 90,50, 110,50, 130,50); _movedraw(180,400, '4.2', 'right line1 overridden by colinearity, left line2 line anyway'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (10,10, 30,10, 50,10, 30,50, 50,50, 70,50); _movedraw(350,400, '4.3', 'like 4.2 but more extreme S-curve'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); _movedraw(480,400, '4.4', 'like 4.3 but longer control points'); $grfx->bspline(\@pts, -debug=>$db, -ratio=>0.75, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # one simple curve row 5 @points = (10,10, 30,50, 90,20, 150,40); _movedraw(30,300, '5.1', 'force line left end, force constrained curve right end'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # force first and last to lines _movedraw(230,300, '5.2', 'force lines both ends, curve tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2'); $grfx->stroke(); _movedraw(400,280, '5.3', 'like 5.2 with longer control points for more extreme S-curve'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line2', -ratio=>1); $grfx->stroke(); # long end colinears row 6 @points = (10,10, 20,12, 30,14, 40,16, 50,18, 60,20, 70,22, 80,24); _movedraw(30,230, '6.1', 'right end line1 overridden to line by colinearity'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # short interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 80,10); _movedraw(120,200, '6.2', 'force left line, right constrained curve, tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 80,50); _movedraw(235,200, '6.3', 'force left line, right constrained curve, tangents match'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # longer interior colinears row 6 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,200, '6.4', 'like 6.2 with extra middle point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,200, '6.5', 'like 6.3 with extra middle point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # even longer interior colinears row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,100, '7.1', 'like 6.4 with new flat center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,100, '7.2', 'like 6.5 with new center point'); $grfx->bspline(\@pts, -debug=>$db, -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # shorter interior colinears with lines row 7 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,10); _movedraw(340,100, '7.3', 'like 6.4 with center segment forced to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 100,50); _movedraw(470,100, '7.4', 'like 6.5 with center segment forced to line'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); # even longer interior colinears row 8 @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,10); _movedraw(30,10, '8.1', 'like 7.1 but center colinear segments forced to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); @points = (20,10, 30,30, 50,30, 70,30, 90,30, 110,30, 120,50); _movedraw(170,10, '8.2', 'like 7.2 but center colinear segments forced to lines'); $grfx->bspline(\@pts, -debug=>$db, -colinear=>'line', -firstseg=>'line2', -lastseg=>'line1'); $grfx->stroke(); $pdf->saveas($PDFname); # --------------------------------------- # move to first set of points, copy remainder into @pts sub _movedraw { my ($hoffset, $voffset, $label, $explain) = @_; if (!defined $explain) { $explain = ''; } #print "$label\n"; $grfx->move($points[0]+$hoffset, $points[1]+$voffset +2); @pts = (); for ($i=2; $i<scalar @points; $i+=2) { $pts[$i-2] = $points[$i] + $hoffset; $pts[$i-1] = $points[$i+1] + $voffset +2; } $text->font($font, 10); $text->translate($hoffset, $voffset); $text->text($label); # explain fitted in a column $text->font($font, 5); my $line_count = 0; my $w; while ($explain ne '') { $text->translate($hoffset+15, $voffset+3-6*$line_count++); ($w, $explain) = $text->text_fill_left($explain, 15*5); } return; } # --------------------------------------- sub nextPage { $pageNo++; $page = $pdf->page(); $grfx = $page->gfx(); $text = $page->text(); $page->mediabox('Universal'); $font = $pdf->corefont('Times-Roman'); $text->translate(595/2,15); $text->font($font, 10); $text->fillcolor('black'); $text->text_center("-$pageNo-"); # prefill page number before any other content return; }