Figure tanh.asy
import graph;
size(100,0);
real f(real x) {return tanh(x);}
pair F(real x) {return (x,f(x));}
xaxis("$x$");
yaxis("$y$");
draw(graph(f,-2.5,2.5,operator ..));
label("$\tanh x$",F(1.5),1.25*N);
Figure textpath.asy
size(300);
fill(texpath(Label("test",TimesRoman())),pink);
fill(texpath(Label("test",fontcommand('.fam T\n.ps 12')),tex=false),red);
pair z=10S;
fill(texpath(Label("$ \sqrt{x^2} $",z,TimesRoman())),pink);
fill(texpath(Label("$ sqrt {x sup 2} $",z,fontcommand('.fam T\n.ps 12')),
tex=false),red);
Figure thermodynamics.asy
// example file for roundedpath() in roundedpath.asy
// written by stefan knorr
// import needed packages
import roundedpath;
// function definition
picture CreateKOOS(real Scale, string legend) // draw labeled coordinate system as picture
{
picture ReturnPic;
real S = 1.2*Scale;
draw(ReturnPic, ((-S,0)--(S,0)), bar = EndArrow); // x axis
draw(ReturnPic, ((0,-S)--(0,S)), bar = EndArrow); // y axis
label(ReturnPic, "$\varepsilon$", (S,0), SW); // x axis label
label(ReturnPic, "$\sigma$", (0,S), SW); // y axis label
label(ReturnPic, legend, (0.7S, -S), NW); // add label 'legend'
return ReturnPic; // return picture
}
// some global definitions
real S = 13mm; // universal scale factor for the whole file
real grad = 0.25; // gradient for lines
real radius = 0.04; // radius for the rounded path'
real lw = 2; // linewidth
pair A = (-1, -1); // start point for graphs
pair E = ( 1, 1); // end point for graphs
path graph; // local graph
pen ActPen; // actual pen for each drawing
picture T[]; // vector of all four diagrams
real inc = 2.8; // increment-offset for combining pictures
//////////////////////////////////////// 1st diagram
T[1] = CreateKOOS(S, "$T_1$"); // initialise T[1] as empty diagram with label $T_1$
graph = A; // # pointwise definition of current path 'graph'
graph = graph -- (A.x + grad*1.6, A.y + 1.6); // #
graph = graph -- (E.x - grad*0.4, E.y - 0.4); // #
graph = graph -- E; // #
graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy
ActPen = rgb(0,0,0.6) + linewidth(lw); // define pen for drawing in 1st diagram
draw(T[1], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[1]' (1st hysteresis branch)
draw(T[1], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (2nd hysteresis branch)
graph = (0,0) -- (grad*0.6, 0.6) -- ( (grad*0.6, 0.6) + (0.1, 0) ); // define branch from origin to hysteresis
graph = roundedpath(graph, radius, S); // round this path
draw(T[1], graph, ActPen); // draw this path into 'T[1]'
//////////////////////////////////////// 2nd diagram
T[2] = CreateKOOS(S, "$T_2$"); // initialise T[2] as empty diagram with label $T_2$
graph = A; // # pointwise definition of current path 'graph'
graph = graph -- (A.x + grad*1.3, A.y + 1.3); // #
graph = graph -- (E.x - grad*0.7 , E.y - 0.7); // #
graph = graph -- E; // #
graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy
ActPen = rgb(0.2,0,0.4) + linewidth(lw); // define pen for drawing in 2nd diagram
draw(T[2], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[2]' (1st hysteresis branch)
draw(T[2], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (2nd hysteresis branch)
graph = (0,0) -- (grad*0.3, 0.3) -- ( (grad*0.3, 0.3) + (0.1, 0) ); // define branch from origin to hysteresis
graph = roundedpath(graph, radius, S); // round this path
draw(T[2], graph, ActPen); // draw this path into 'T[2]'
//////////////////////////////////////// 3rd diagram
T[3] = CreateKOOS(S, "$T_3$"); // initialise T[3] as empty diagram with label $T_3$
graph = A; // # pointwise definition of current path 'graph'
graph = graph -- (A.x + grad*0.7, A.y + 0.7); // #
graph = graph -- ( - grad*0.3 , - 0.3); // #
graph = graph -- (0,0); // #
graph = graph -- (grad*0.6, 0.6); // #
graph = graph -- (E.x - grad*0.4, E.y - 0.4); // #
graph = graph -- E; // #
graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy
ActPen = rgb(0.6,0,0.2) + linewidth(lw); // define pen for drawing in 3rd diagram
draw(T[3], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[3]' (1st hysteresis branch)
draw(T[3], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (2nd hysteresis branch)
//////////////////////////////////////// 4th diagram
T[4] = CreateKOOS(S, "$T_4$"); // initialise T[4] as empty diagram with label $T_4$
graph = A; // # pointwise definition of current path 'graph'
graph = graph -- (A.x + grad*0.4, A.y + 0.4); // #
graph = graph -- ( - grad*0.6 , - 0.6); // #
graph = graph -- (0,0); // #
graph = graph -- (grad*0.9, 0.9); // #
graph = graph -- (E.x - grad*0.1, E.y - 0.1); // #
graph = graph -- E; // #
graph = roundedpath(graph, radius, S); // round edges of 'graph' using roundedpath() in roundedpath.asy
ActPen = rgb(0.6,0,0) + linewidth(lw); // define pen for drawing in 4th diagram
draw(T[4], graph, ActPen); // draw 'graph' with 'ActPen' into 'T[4]' (1st hysteresis branch)
draw(T[4], rotate(180,(0,0))*graph, ActPen); // draw rotated 'graph' (3nd hysteresis branch)
// add some labels and black dots to the first two pictures
pair SWW = (-0.8, -0.6);
label(T[1], "$\sigma_f$", (0, 0.6S), NE); // sigma_f
draw(T[1], (0, 0.6S), linewidth(3) + black);
label(T[2], "$\sigma_f$", (0, 0.3S), NE); // sigma_f
draw(T[2], (0, 0.3S), linewidth(3) + black);
label(T[1], "$\varepsilon_p$", (0.7S, 0), SWW); // epsilon_p
draw(T[1], (0.75S, 0), linewidth(3) + black);
label(T[2], "$\varepsilon_p$", (0.7S, 0), SWW); // epsilon_p
draw(T[2], (0.75S, 0), linewidth(3) + black);
// add all pictures T[1...4] to the current one
add(T[1],(0,0));
add(T[2],(1*inc*S,0));
add(T[3],(2*inc*S,0));
add(T[4],(3*inc*S,0));
// draw line of constant \sigma and all intersection points with the graphs in T[1...4]
ActPen = linewidth(1) + dashed + gray(0.5); // pen definition
draw((-S, 0.45*S)--((3*inc+1)*S, 0.45*S), ActPen); // draw backgoundline
label("$\sigma_s$", (-S, 0.45S), W); // label 'sigma_s'
path mark = scale(2)*unitcircle; // define mark-symbol to be used for intersections
ActPen = linewidth(1) + gray(0.5); // define pen for intersection mark
draw(shift(( 1 - grad*0.55 + 0*inc)*S, 0.45*S)*mark, ActPen); // # draw all intersections
draw(shift((-1 + grad*1.45 + 0*inc)*S, 0.45*S)*mark, ActPen); // #
draw(shift(( 1 - grad*0.55 + 1*inc)*S, 0.45*S)*mark, ActPen); // #
draw(shift(( 1 - grad*0.55 + 2*inc)*S, 0.45*S)*mark, ActPen); // #
draw(shift(( grad*0.45 + 2*inc)*S, 0.45*S)*mark, ActPen); // #
draw(shift(( grad*0.45 + 3*inc)*S, 0.45*S)*mark, ActPen); // #
Figure treetest.asy
import drawtree;
treeLevelStep = 2cm;
TreeNode root = makeNode( "Root" );
TreeNode child1 = makeNode( root, "Child\_1" );
TreeNode child2 = makeNode( root, "Child\_2" );
TreeNode gchild1 = makeNode( child1, "Grandchild\_1" );
TreeNode gchild2 = makeNode( child1, "Grandchild\_2" );
TreeNode gchild3 = makeNode( child1, "Grandchild\_3" );
TreeNode gchild4 = makeNode( child1, "Grandchild\_4" );
TreeNode gchild11 = makeNode( child2, "Grandchild\_1" );
TreeNode gchild22 = makeNode( child2, "Grandchild\_2" );
TreeNode ggchild1 = makeNode( gchild1, "Great Grandchild\_1" );
draw( root, (0,0) );
Figure triangle.asy
size(0,100);
import geometry;
triangle t=triangle(b=3,alpha=90,c=4);
dot((0,0));
draw(t);
draw(rotate(90)*t,red);
draw(shift((-4,0))*t,blue);
draw(reflect((0,0),(1,0))*t,green);
draw(slant(2)*t,magenta);
Figure tvgen.asy
/* tvgen - draw pm5544-like television test cards.
* Copyright (C) 2007, 2009, Servaas Vandenberghe.
*
* The tvgen code below is free software: you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with tvgen: see the file COPYING. If not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
* tvgen-1.1/tvgen.asy
* This asy script generates pm5544-like television test cards. The image
* parameters were derived from a 1990 recording. The basic parameters
* conform to itu-r bt.470, bt.601, and bt.709. There is no unique image
* since local variants exist and parameters have varied over time.
*/
//papertype="a4";
import plain;
int verbose=settings.verbose/*+2*/; /* uncomment for debug info */
/* tv dot coordinates --> PS points */
pair tvps(real col, real row, real xd, real yd, int Nv) {
real psx, psy;
psx=col*xd; psy=(Nv-row)*yd;
return (psx,psy);
}
path tvrect(int lc, int tr, int rc, int br, real xd, real yd, int Nv) {
real lx, ty, rx, by;
pair[] z;
lx=lc*xd; ty=(Nv-tr)*yd;
rx=rc*xd; by=(Nv-br)*yd;
/* bl br tr tl */
z[0]=(lx, by);
z[1]=(rx, by);
z[2]=(rx, ty);
z[3]=(lx, ty);
return z[0]--z[1]--z[2]--z[3]--cycle;
}
/********************* image aspect ratio markers ********************/
void rimarkers(real rimage, int Nh, int Nhc, int os, int Nvc, int Nsy, pen pdef, real xd, real yd, int Nv) {
int[] ridefN={ 4, 16 };
int[] ridefD={ 3, 9 };
int i;
for(i=0; i<2; ++i) {
real rid=ridefN[i]/ridefD[i];
if(rimage>rid) {
int off, offa, offb;
/* Nhdef=Nh/rimage*rid */
off=round(Nh/rimage*rid/2);
offa=off+os;
offb=off-os;
// write(offa,offb);
if(2*offa<Nh) {
int hy, tr, br;
path zz;
hy=floor(Nsy/3);
tr=Nvc-hy;
br=Nvc+hy;
zz=tvrect(Nhc+offb, tr, Nhc+offa, br, xd,yd,Nv);
//dot(zz);
fill(zz, p=pdef);
zz=tvrect(Nhc-offa, tr, Nhc-offb, br, xd,yd,Nv);
fill(zz, p=pdef);
}
}
} /* for i */
return;
}
/************* cross hatch: line pairing, center interlace test *************/
void centerline(int[] coff, int[] coffa, int[] coffb, int Nhc, int divsx,
int os, int[] rcrowc, int Nvc, int divsy,
pair ccenter, real[] rcoff, pair[] rcright, pair[] rcleft,
pen pdef, real xd, real yd, int Nv) {
pair[] z;
int col;
pen pblack=pdef+gray(0.0), pwhite=pdef+gray(1.0);
z[0]=rcright[divsy];
col=Nhc+coff[0];
z[1]=tvps(col,rcrowc[divsy], xd,yd,Nv);
z[2]=tvps(col,rcrowc[divsy-1], xd,yd,Nv);
col=Nhc-coff[0];
z[3]=tvps(col,rcrowc[divsy-1], xd,yd,Nv);
z[4]=tvps(col,rcrowc[divsy], xd,yd,Nv);
z[5]=rcleft[divsy];
z[6]=rcleft[divsy+1];
z[7]=tvps(col,rcrowc[divsy+1], xd,yd,Nv);
z[8]=tvps(col,rcrowc[divsy+2], xd,yd,Nv);
col=Nhc+coff[0];
z[9]=tvps(col,rcrowc[divsy+2], xd,yd,Nv);
z[10]=tvps(col,rcrowc[divsy+1], xd,yd,Nv);
z[11]=rcright[divsy+1];
fill(z[1]--z[2]--z[3]--z[4] //--z[5]--z[6]
--arc(ccenter, z[5], z[6])
--z[7]--z[8]--z[9]--z[10] //--z[11]--z[0]
--arc(ccenter,z[11], z[0])
--cycle, p=pblack);
int i, maxoff, rows, tr, br;
path zz;
maxoff=floor(rcoff[divsy]);
/* center cross: vertical and horizontal centerline */
rows=min(Nvc-rcrowc[divsy-1], rcrowc[divsy+2]-Nvc);
tr=Nvc-rows;
br=Nvc+rows;
//write("centerline long: rows tr br ", rows, tr, br);
zz=tvrect(Nhc-os, tr, Nhc+os, br, xd,yd,Nv);
fill(zz, p=pwhite);
zz=tvrect(Nhc-maxoff,Nvc-1, Nhc+maxoff,Nvc+1, xd,yd,Nv);
fill(zz, p=pwhite);
/* vertical short lines */
rows=min(Nvc-rcrowc[divsy], rcrowc[divsy+1]-Nvc);
tr=Nvc-rows;
br=Nvc+rows;
if(verbose>1)
write("centerline: rows tr br ", rows, tr, br);
for(i=0; i<=divsx; ++i) {
int off;
off=coff[i];
if(off<maxoff) {
int offa, offb;
path zzv;
offa=coffa[i];
offb=coffb[i];
zzv=tvrect(Nhc+offb, tr, Nhc+offa, br, xd,yd,Nv);
fill(zzv, p=pwhite);
zzv=tvrect(Nhc-offa, tr, Nhc-offb, br, xd,yd,Nv);
fill(zzv, p=pwhite);
}
}
return;
}
/************************ topbw **************************************/
void topbw(int[] coff, int Nhc, int os, int urow, int trow, int brow,
pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb,
pen pdef, real xd, real yd, int Nv) {
pen pblack=pdef+gray(0.0), pwhite=pdef+gray(1.0);
pair[] ze;
path zext, zref, zint;
int off, col, cr;
off=ceil((coff[2]+coff[3])/2);
ze[0]=tvps(Nhc+off,trow, xd,yd,Nv);
ze[1]=rcrt;
ze[2]=rclt;
ze[3]=tvps(Nhc-off,trow, xd,yd,Nv);
ze[4]=tvps(Nhc-off,brow, xd,yd,Nv);
col=Nhc-coff[2]-os;
ze[5]=tvps(col,brow, xd,yd,Nv);
ze[6]=tvps(col,trow, xd,yd,Nv);
cr=col+3*os; /* reflection test black pulse */
zref=tvrect(col,trow, cr,brow, xd,yd,Nv);
ze[7]=tvps(cr,trow, xd,yd,Nv);
ze[8]=tvps(cr,brow, xd,yd,Nv);
ze[9]=tvps(Nhc+off,brow, xd,yd,Nv);
//dot(ze);
zext=ze[0] // --ze[1]--ze[2]
--arc(ccenter, ze[1], ze[2])
--ze[3]--ze[4]--ze[5]--ze[6]--ze[7]--ze[8]--ze[9]--cycle;
off=ceil((coff[1]+coff[2])/2);
zint=tvrect(Nhc-off,urow, Nhc+off,trow, xd,yd,Nv);
/* paths are completely resolved; no free endpoint conditions */
fill(zext^^reverse(zint), p=pwhite);
fill(zint, p=pblack);
fill(zref, p=pblack);
fill(arc(ccenter,rclt,rclb)--ze[4]--ze[3]--cycle, p=pblack);
fill(arc(ccenter,rcrb,rcrt)--ze[0]--ze[9]--cycle, p=pblack);
return;
}
/************************ testtone **************************************/
/* x on circle -> return y>=0
* in:
* x x-coordinate relative to origin
* crad circle radius in y units, true size=crad*yd
*/
real testcircx(real x, real crad, real xd, real yd) {
real relx, phi, y;
relx=x*xd/yd/crad;
if(relx>1) {
phi=0;
} else {
phi=acos(relx);
}
y=crad*sin(phi); // or (x*xd)^2+(y*yd)^2=(crad*yd)^2
return y;
}
/* y on circle -> return x>=0 */
real testcircy(real y, real crad, real xd, real yd) {
real rely, phi, x;
rely=y/crad;
if(rely>1) {
phi=pi/2;
} else {
phi=asin(rely);
}
x=crad*cos(phi)*yd/xd; // or (x*xd)^2+(y*yd)^2=(crad*yd)^2
return x;
}
/* brow>trow && xb>xt */
void testtone(real Tt, int trow, int brow,
real ccol, real crow, real crad,
pen pdef, real xd, real yd, int Nv) {
int blocks, i;
real yt, xt, yb, xb, Ttt=Tt/2;
pair ccenter;
yt=crow-trow;
xt=testcircy(yt, crad, xd, yd);
yb=crow-brow;
xb=testcircy(yb, crad, xd, yd);
//write('#xt yt\t',xt,yt); write('#xb yb\t',xb,yb);
ccenter=tvps(ccol,crow, xd,yd,Nv);
blocks=floor(2*xb/Tt);
for(i=-blocks-1; i<=blocks; ++i) {
real tl, tr;
path zz;
tl=max(-xb,min(i*Ttt,xb)); /* limit [-xb..xb] */
tr=max(-xb,min((i+1)*Ttt,xb));
if(tl<-xt && tr<=-xt || tr>xt && tl>=xt) { /* top full circle */
pair[] z;
real yl, yr;
yl=testcircx(tl, crad, xd, yd);
yr=testcircx(tr, crad, xd, yd);
z[0]=tvps(ccol+tl,brow, xd,yd,Nv);
z[1]=tvps(ccol+tr,brow, xd,yd,Nv);
z[2]=tvps(ccol+tr,crow-yr, xd,yd,Nv);
z[3]=tvps(ccol+tl,crow-yl, xd,yd,Nv);
zz=z[0]--z[1]--arc(ccenter,z[2],z[3])--cycle;
} else if(tl<-xt) { /* tl in circel, tr not, partial */
pair[] z;
real yl;
yl=testcircx(tl, crad, xd, yd);
z[0]=tvps(ccol+tl,brow, xd,yd,Nv);
z[1]=tvps(ccol+tr,brow, xd,yd,Nv);
z[2]=tvps(ccol+tr,trow, xd,yd,Nv);
z[3]=tvps(ccol-xt,trow, xd,yd,Nv);
z[4]=tvps(ccol+tl,crow-yl, xd,yd,Nv);
zz=z[0]--z[1]--z[2]--arc(ccenter,z[3],z[4])--cycle;
} else if(tr>xt) { /* tr in circle, tl not, partial */
pair[] z;
real yr;
yr=testcircx(tr, crad, xd, yd);
z[0]=tvps(ccol+tl,brow, xd,yd,Nv);
z[1]=tvps(ccol+tr,brow, xd,yd,Nv);
z[2]=tvps(ccol+tr,crow-yr, xd,yd,Nv);
z[3]=tvps(ccol+xt,trow, xd,yd,Nv);
z[4]=tvps(ccol+tl,trow, xd,yd,Nv);
zz=z[0]--z[1]--arc(ccenter,z[2],z[3])--z[4]--cycle;
} else { /* full block */
pair[] z;
z[0]=tvps(ccol+tr,trow, xd,yd,Nv);
z[1]=tvps(ccol+tl,trow, xd,yd,Nv);
z[2]=tvps(ccol+tl,brow, xd,yd,Nv);
z[3]=tvps(ccol+tr,brow, xd,yd,Nv);
zz=z[0]--z[1]--z[2]--z[3]--cycle;
}
if(tl<tr) {
if(i%2 == 0) {
fill(zz, p=pdef+gray(0.0));
} else {
fill(zz, p=pdef+gray(0.75));
}
}
}
return;
}
/************************ color bars *************************************/
void colorbars(int[] coff, int Nhc, int trow, int crow, int brow,
pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb,
pen pdef, real xd, real yd, int Nv) {
real cI=0.75;
real[] cR={ cI, 0, 0, cI, cI, 0 };
real[] cG={ cI, cI, cI, 0, 0, 0 };
real[] cB={ 0, cI, 0, cI, 0, cI };
int cmax=2, poff, rows, i;
rows=brow-trow;
poff=0;
for(i=0; i<=cmax; ++i) {
int off;
int ii=2*i, il=cmax-i, ir=i+cmax+1;
path zzl, zzr;
off=ceil((coff[1+ii]+coff[2+ii])/2);
if(i!=0 && i<cmax) {
zzr=tvrect(Nhc+poff,trow, Nhc+off,brow, xd,yd,Nv);
zzl=tvrect(Nhc-off,trow, Nhc-poff,brow, xd,yd,Nv);
} else {
if(i==0) {
int col, pcol;
pair[] zl, zr;
col=Nhc+off;
pcol=Nhc+poff;
zr[0]=tvps(col,trow, xd,yd,Nv);
zr[1]=tvps(pcol,trow, xd,yd,Nv);
zr[2]=tvps(pcol,crow, xd,yd,Nv);
zr[3]=tvps(Nhc+coff[0],crow, xd,yd,Nv);
zr[4]=tvps(Nhc+coff[0],brow, xd,yd,Nv);
zr[5]=tvps(col,brow, xd,yd,Nv);
zzr=zr[0]--zr[1]--zr[2]--zr[3]--zr[4]--zr[5]--cycle;
col=Nhc-off;
pcol=Nhc-poff;
zl[0]=tvps(pcol,trow, xd,yd,Nv);
zl[1]=tvps(col,trow, xd,yd,Nv);
zl[2]=tvps(col,brow, xd,yd,Nv);
zl[3]=tvps(Nhc-coff[0],brow, xd,yd,Nv);
zl[4]=tvps(Nhc-coff[0],crow, xd,yd,Nv);
zl[5]=tvps(pcol,crow, xd,yd,Nv);
zzl=zl[0]--zl[1]--zl[2]--zl[3]--zl[4]--zl[5]--cycle;
} else {
int pcol;
pair[] zl, zr;
pcol=Nhc+poff;
zr[0]=tvps(pcol,brow, xd,yd,Nv);
zr[1]=rcrb;
zr[2]=rcrt;
zr[3]=tvps(pcol,trow, xd,yd,Nv);
zzr=zr[0]--arc(ccenter,zr[1],zr[2])--zr[3]--cycle;
pcol=Nhc-poff;
zl[0]=tvps(pcol,trow, xd,yd,Nv);
zl[1]=rclt;
zl[2]=rclb;
zl[3]=tvps(pcol,brow, xd,yd,Nv);
zzl=zl[0]--arc(ccenter,zl[1],zl[2])--zl[3]--cycle;
}
}
fill(zzr, p=pdef+rgb(cR[ir], cG[ir], cB[ir]));
fill(zzl, p=pdef+rgb(cR[il], cG[il], cB[il]));
poff=off;
}
return;
}
/************************ test frequencies ****************************/
/* in
* theta rad
* freq 1/hdot
* step hdot
* out
* new phase theta
*/
real addphase(real theta, real freq, real step) {
real cycles, thetaret;
int coverflow;
cycles=freq*step;
coverflow=floor(abs(cycles));
if(coverflow>1) {
thetaret=0;
} else {
real dpi=2*pi;
cycles-=coverflow*sgn(cycles);
thetaret=theta+cycles*dpi; /* cycles=(-1 .. 1) */
if(thetaret>pi) {
thetaret-=dpi;
} else if(thetaret<-pi) {
thetaret-=dpi;
}
}
//write("addphase: ", step, theta, thetaret);
return thetaret;
}
void testfreqs(real[] ftones, int[] coff, int Nhc, int trow,int crow,int brow,
pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb,
pen pdef, real xd, real yd, int Nv) {
int[] divc;
real[] divfl, divfr;
int i, divs, coffmax, off, divnext;
real fl, fr, thr, thl;
/* Segment info for PAL continental test card
* segment i extends from [divc[i] .. divc[i+1]) with frequency divf[i]
*/
divs=2; // the number of segments on the right, total=2*divs+1
divc[0]=0;
for(i=0; i<=divs; ++i) {
int ii=i*2, il=divs-i, ir=divs+i;
divc[i+1]=ceil((coff[ii]+coff[ii+1])/2); /* xdot distance to center */
divfl[i]=ftones[divs-i];
divfr[i]=ftones[divs+i];
}
coffmax=divc[divs+1];
int trowlim=coff[0];
int tr;
tr=crow;
divnext=0;
fl=0;
fr=0;
thl=0;
thr=0;
// draw a vertical line at off..off+1
for(off=0; off<coffmax; ++off) {
real ampl, ampr;
int col;
path zz;
if(off==trowlim) {
tr=trow;
}
if(off == divc[divnext]) {
/* switch frequency: cycles=0.5*fcur+0.5*fnext */
thl=addphase(thl, fl, -0.5);
thr=addphase(thr, fr, 0.5);
fl=divfl[divnext];
fr=divfr[divnext];
thl=addphase(thl, fl, -0.5);
thr=addphase(thr, fr, 0.5);
++divnext;
// thl=pi; thr=pi;
//write(off, fl, fr);
} else {
thl=addphase(thl, fl, -1);
thr=addphase(thr, fr, 1);
// thl=0; thr=0;
}
ampl=(1+sin(thl))/2;
ampr=(1+sin(thr))/2;
//write(off, thr, ampr);
col=Nhc-off-1;
zz=tvrect(col,tr, col+1,brow, xd,yd,Nv);
fill(zz, p=pdef+gray(ampl));
col=Nhc+off;
zz=tvrect(col,tr, col+1,brow, xd,yd,Nv);
fill(zz, p=pdef+gray(ampr));
}
pair[] z;
z[0]=tvps(Nhc-coffmax,trow, xd,yd,Nv);
z[1]=tvps(Nhc-coffmax,brow, xd,yd,Nv);
fill(z[0]--arc(ccenter,rclt,rclb)--z[1]--cycle, p=pdef+gray(0.0));
z[0]=tvps(Nhc+coffmax,brow, xd,yd,Nv);
z[1]=tvps(Nhc+coffmax,trow, xd,yd,Nv);
fill(z[0]--arc(ccenter,rcrb,rcrt)--z[1]--cycle, p=pdef+gray(0.0));
return;
}
/************************ gray bars **************************************/
void graybars(int[] coff, int Nhc, int trow, int brow,
pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb,
pen pdef, real xd, real yd, int Nv) {
int[] gs={0, 51, 102, 153, 204, 255};
int cmax=2, poff, rows, i;
rows=brow-trow;
poff=0;
for(i=0; i<=cmax; ++i) {
int off;
int ii=2*i, il=cmax-i, ir=i+cmax+1;
path zzl, zzr;
off=ceil((coff[1+ii]+coff[2+ii])/2);
if(i<cmax) {
zzl=tvrect(Nhc-off,trow, Nhc-poff,brow, xd,yd,Nv);
zzr=tvrect(Nhc+poff,trow, Nhc+off,brow, xd,yd,Nv);
} else {
int pcol;
pair zlt, zlb, zrt, zrb;
pcol=Nhc-poff;
zlt=tvps(pcol,trow, xd,yd,Nv);
zlb=tvps(pcol,brow, xd,yd,Nv);
zzl=zlt--arc(ccenter,rclt,rclb)--zlb--cycle;
pcol=Nhc+poff;
zrb=tvps(pcol,brow, xd,yd,Nv);
zrt=tvps(pcol,trow, xd,yd,Nv);
zzr=zrb--arc(ccenter,rcrb,rcrt)--zrt--cycle;
}
fill(zzl, p=pdef+gray(gs[il]/255));
fill(zzr, p=pdef+gray(gs[ir]/255));
poff=off;
}
return;
}
/************************ bottom bw **************************************/
void bottombw(int off, int Nhc, int trow, int brow,
pair ccenter, pair rclt, pair rclb, pair rcrt, pair rcrb,
pen pdef, real xd, real yd, int Nv) {
int rows;
pair zt, zb;
path zz;
rows=brow-trow;
zz=tvrect(Nhc-off,trow, Nhc+off,brow, xd,yd,Nv);
fill(zz, p=pdef+gray(0.0));
zt=tvps(Nhc-off,trow, xd,yd,Nv);
zb=tvps(Nhc-off,brow, xd,yd,Nv);
fill(zt--arc(ccenter,rclt,rclb)--zb--cycle, p=pdef+gray(1.0));
zb=tvps(Nhc+off,brow, xd,yd,Nv);
zt=tvps(Nhc+off,trow, xd,yd,Nv);
fill(zb--arc(ccenter,rcrb,rcrt)--zt--cycle, p=pdef+gray(1.0));
return;
}
/************************ bottom circle **************************************/
void bottomcirc(int off, int Nhc, int trow, real cx, real cy, real crad,
pair ccenter, pair rclt, pair rcrt,
pen pdef, real xd, real yd, int Nv) {
real cI=0.75;
real xl, yl, xr, yr, phil, phir;
pair ccleft, ccright;
pair[] z;
xl=Nhc-off-cx;
phil=acos(xl*xd/yd/crad);
yl=crad*sin(phil); // or (x*xd)^2+(y*yd)^2=(crad*yd)^2
ccleft=tvps(cx+xl,cy+yl, xd,yd,Nv);
//write(xl,yl);
xr=Nhc+off-cx;
phir=acos(xr*xd/yd/crad);
yr=crad*sin(phir);
ccright=tvps(cx+xr,cy+yr, xd,yd,Nv);
//dot(ccright); dot(ccleft);
// red center
z[0]=tvps(Nhc-off,trow, xd,yd,Nv);
z[1]=ccleft;
z[2]=ccright;
z[3]=tvps(Nhc+off,trow, xd,yd,Nv);
fill(z[0]--arc(ccenter,z[1],z[2])--z[3]--cycle, p=pdef+rgb(cI,0,0));
// yellow
z[0]=tvps(Nhc-off,trow, xd,yd,Nv);
z[1]=rclt;
z[2]=ccleft;
fill(z[0]--arc(ccenter,z[1],z[2])--cycle, p=pdef+rgb(cI,cI,0));
z[0]=tvps(Nhc+off,trow, xd,yd,Nv);
z[1]=ccright;
z[2]=rcrt;
fill(z[0]--arc(ccenter,z[1],z[2])--cycle, p=pdef+rgb(cI,cI,0));
return;
}
/****************************** PAL ears ***********************************
* left y R G B
* 0.55 98 162 140
* 0.5 103 128 191
* 0.5 152 128 64
* 0.45 157 93 115
* right
* 0.6 153 168 76
* 0.4 102 87 179
*
* in: dright= -1 left ear, +1 right ear
*/
void palears(int[] coff, int[] coffa, int[] coffb, int Nhc,
int[] rcrowt, int[] rcrowb, int Nvc, int divsy, int dright,
pen pdef, real xd, real yd, int Nv) {
/* the amplitude of (u,v) as seen on a vectorscope,
* max 0.296 Vn for 100% saturation in W and V ears.
* cvbs: 0.7*( y +/- |u+jv| ) = -0.24 .. 0.93 V
* maxima: ebu 75/0 bars 0.70, bbc 100/25 0.88, 100/0 bars 0.93
* burst: 0.150 Vcvbs, 21.4 IRE or 0.214 V normalized.
* luma: modulated for monochrome compatibility, 1990 version.
* choice: set amplitude of subcarrier equal to amplitude of colorburst.
*/
real cI=0.214;
/* (u,v) for zero G-y, phase of -34.5 degrees */
real wr=0.299, wb=0.114, wg=1-wr-wb; /* wg=0.587, y=wr*R+wg*G+wb*B */
real wu=0.493, wv=0.877; /* u=wu*(B-y) v=wv*(R-y) */
real colu=wu*wg/wb, colv=-wv*wg/wr; /* for w=(G-y)/0.696 == 0 */
/* ears: U==0 W==0 W==0 U==0 */
real[] cyl={ 0.55, 0.5, 0.5, 0.45 };
real[] cul={ 0, colu, -colu, 0 };
real[] cvl={ -1, colv, -colv, 1 };
/* ears: V==0 W==0 W==0 V==0 */
real[] cyr={ 0.60, 0.5, 0.5, 0.40 };
real[] cur={ -1, colu, -colu, 1 };
real[] cvr={ 0, colv, -colv, 0 };
real[] cy, cu, cv;
pair[] z;
path[] zz;
int lcol, ccol, cicol, rcol, i;
if(dright>0) {
cy=cyr; cu=cur; cv=cvr;
} else {
cy=cyl; cu=cul; cv=cvl;
}
lcol=Nhc+dright*coffa[5];
ccol=Nhc+dright*coff[6];
cicol=Nhc+dright*coffa[6];
rcol=Nhc+dright*coffb[7];
int urow, trow, crow, brow, arow;
urow=rcrowb[divsy-5];
trow=rcrowt[divsy-3];
crow=Nvc;
brow=rcrowb[divsy+4];
arow=rcrowt[divsy+6];
z[0]=tvps(ccol,urow, xd,yd,Nv);
z[1]=tvps(ccol,trow, xd,yd,Nv);
z[2]=tvps(cicol,trow, xd,yd,Nv);
z[3]=tvps(cicol,crow, xd,yd,Nv);
z[4]=tvps(rcol,crow, xd,yd,Nv);
z[5]=tvps(rcol,urow, xd,yd,Nv);
zz[0]=z[0]--z[1]--z[2]--z[3]--z[4]--z[5]--cycle;
zz[1]=tvrect(lcol,urow, ccol,trow, xd,yd,Nv);
zz[2]=tvrect(lcol,brow, ccol,arow, xd,yd,Nv);
z[0]=tvps(ccol,arow, xd,yd,Nv);
z[1]=tvps(ccol,brow, xd,yd,Nv);
z[2]=tvps(cicol,brow, xd,yd,Nv);
z[3]=tvps(cicol,crow, xd,yd,Nv);
z[4]=tvps(rcol,crow, xd,yd,Nv);
z[5]=tvps(rcol,arow, xd,yd,Nv);
zz[3]=z[0]--z[1]--z[2]--z[3]--z[4]--z[5]--cycle;
for(i=0; i<4; ++i) {
real y, u, v, A, ph, By, Ry, Gy, R, G, B;
y=cy[i];
u=cu[i];
v=cv[i];
A=hypot(u,v);
ph= (u!=0 || v!=0) ? atan2(v,u) : 0.0;
if(v>=0) {
if(ph<0) ph=ph+pi;
} else {
if(ph>0) ph=ph-pi;
}
if(A>0) {
u=u/A*cI;
v=v/A*cI;
}
By=u/wu;
Ry=v/wv;
Gy=(-wr*Ry-wb*By)/wg;
//write(y,Gy,A,ph*180/pi);
R=Ry+y;
G=Gy+y;
B=By+y;
if(verbose > 1)
write(y,round(R*255),round(G*255),round(B*255));
fill(zz[i], p=pdef+rgb(R,G,B));
}
return;
}
/****************************** NTSC bars ***********************************
* amplitude equals color burst smpte (pm: -V +U)
* y campl sat R G B
* left 0.5 0.21 70% -I?
* right 0.5 0.17 60% +Q?
*/
void ntscbars(int[] coff, int[] coffa, int[] coffb, int Nhc,
int[] rcrowt, int[] rcrowb, int Nvc, int divsy, int dright,
pen pdef, real xd, real yd, int Nv) {
/* The amplitude of (i,q) as seen on a vectorscope,
* max 0.292 Vn for 100% saturation in I==0 ears.
* burst: 0.143 Vcvbs, 20 IRE or 0.200 V normalized.
* pedestal: (yp,up,vp)=(p,0,0)+(1-p)*(y,u,v), p=0.075.
* choice: equal amplitude for colorburst and subcarrier.
*/
real campl=0.200/0.925;
/* wg=0.587, y=wr*R+wg*G+wb*B */
real wr=0.299, wb=0.114, wg=1-wr-wb;
/* iT : iq -> RyBy : rotation+scaling */
real iT11=0.95, iT12=0.62, iT21=-1.11, iT22=1.71;
/* bars -2 -1 0 1 2 */
real[] cyl={ 0.50, 0.50, 0, 0.50, 0.50 };
real[] cil={ 0, 0, 0, -1, 1 };
real[] cql={ -1, 1, 0, 0, 0 };
int[] offil={ 6, 7, 5, 7, 6 };
real cy, ci, cq;
int dri, dris, offi, lcol, rcol, i;
if(dright>=0) {
dris=1;
} else {
dris=-1;
}
if(dright<-2 || dright>2) {
dri=2;
} else {
dri=2+dright;
}
cy=cyl[dri]; ci=cil[dri]; cq=cql[dri];
offi=offil[dri];
lcol=Nhc+dris*coffa[offi];
rcol=Nhc+dris*coffb[offi+1];
real A, By, Ry, Gy, R, G, B;
A=hypot(ci,cq);
if(A>0) {
ci=ci/A*campl;
cq=cq/A*campl;
}
Ry=iT11*ci+iT12*cq;
By=iT21*ci+iT22*cq;
Gy=(-wr*Ry-wb*By)/wg;
//write(cy,Ry,Gy,By);
R=Ry+cy;
G=Gy+cy;
B=By+cy;
if(verbose > 1)
write(cy,ci,cq,round(R*255),round(G*255),round(B*255));
for(i=-divsy; i<=divsy; ++i) {
path zz;
int brow, trow;
if(i>-divsy) {
trow=rcrowb[divsy+i];
} else {
trow=floor((rcrowb[divsy+i]+rcrowt[divsy+i+1])/2);
}
if(divsy>i) {
brow=rcrowt[divsy+i+1];
} else {
brow=floor((rcrowb[divsy+i]+rcrowt[divsy+i+1])/2);
}
zz=tvrect(lcol,brow, rcol,trow, xd,yd,Nv);
fill(zz, p=pdef+rgb(R,G,B));
}
return;
}
/****************************** main ***********************************/
/* Conversion to bitmap:
* EPSPNG='gs -dQUIET -dNOPAUSE -dBATCH -sDEVICE=png16m'
* asy -u bsys=2 -u colortv=1 -u os=1 -a Z tvgen
* $EPSPNG -r132x144 -g720x576 -sOutputFile=tvgen.png tvgen.eps
*
* asy -u bsys=2 -u colortv=1 -u os=1 tvgen
*/
int bsys=2, colortv=1, os=1;
/* bsys: broadcast system
* bsys im aspect Nh
* 0 4/3 704 guaranteed analog broadcast itu-r bt.470
* 1 4/3 720 new broadcast, most TV station logos and animations
* 2 15/11 720 total aperture analog 4/3, 1.37 film DVDs
* 3 20/11 720 total aperture analog 16/9, 1.85 film DVDs
* 4 4/3 768 bsys=0, square dot analog broadcast
* 5 4/3 768 bsys=1, square dot cable TV info channel
* 6 131/96 786 bsys=2, total square dot broadcast camera
* 7 16/9 720 new broadcast 16/9, SD from HD-1440 or itu-r bt.709
* 8 4/3 704 525 analog broadcast itu-r bt.470 711*485
* 9 4/3 720 525 new broadcast
* 10 15/11 720 525 total aperture analog broadcast
* 11 16/9 1920 1250, 1080 square dot at 12.5 frames/second
* 12 4/3 1600 1250, 1200 square dot at 12.5 frames/second
*
* colortv:
* set 0 for monochrome crosshatch, 1 for pal ears, 2 for ntsc bars
*
* os: horizontal oversampling, typical values for 13.5MHz:
* 2 4/3 704*576, 15/11 720*576
* 4 4/3 720*480
* 5 4/3 704*480, 15/11 720*480, 4/3 768*576 14.4MHz
* 8 4/3 720*576, 20/11 720*576
* 12 704->768 rerastering
* 16 720->768 rerastering
*/
access settings;
usersetting();
if(bsys<0 || bsys>12 || colortv<0 || colortv>3 || os<=0 || os>16) {
write('Error: bad user input: bsys, colortv, os=\t', bsys, colortv, os);
abort('Bad option -u bsys=N ?');
}
int[] bNdot=
{ 12, 16, 12, 16, 1, 1, 1, 64, 10, 8, 10, 1, 1 };
int[] bDdot=
{ 11, 15, 11, 11, 1, 1, 1, 45, 11, 9, 11, 1, 1 };
int[] bNh=
{ 704, 720, 720, 720, 768, 768, 786, 720, 704, 720, 720, 1920, 1600 };
int[] bNv=
{ 576, 576, 576, 576, 576, 576, 576, 576, 480, 480, 480, 1080, 1200 };
real[] bfs=
{ 13.5,13.5,13.5,13.5, 14.75,14.4,14.75,13.5, 13.5,13.5,13.5, 36, 30 };
int[] bNsy=
{ 42, 42, 42, 42, 42, 42, 42, 42, 34, 34, 34, 78, 90 };
int[] bNsh=
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
/* active lines for a 625 line frame
* The number of active video lines decreased around 1997.
* old: 3 run in + 575 visible + 3 run out = 581 lines
* new: 6 teletext and WSS + 575 visible
* Hence the image center shifted down by 3 lines. Thus
* old TV + new testcard = bottom is cut off,
* new TV + old testcard = top is cut off.
*
* To generate the old testcard either use Nv=582 Nsh=0 or Nv=576 Nsh=3.
*
* aspect ratio
* rimage=xsize/ysize rimage=rdot*Nh/Nv
* Nh=704 dots
* Nv=576 lines
* rd=ri*Nv/Nh=4/3*9/11=12/11
*
* Nv: 480=2^5*3*5 576=2^6*3^2
* Nh: 704=2^6*11 720=2^4*3^2*5
*
* horizontal line distance for pre 1997 test pattern
* top 8 lines, 13 squares of Ny=43 lines, bottom 9 lines
* top 12 lines, 13 squares of Ny=42 lines, bottom 18 lines
* pairs are from odd even field
* Interlace test: Ny must be odd for a cross-hatch without centerline.
*
* squares: ly=Nsy, lx=rd*Nsx, lx=ly ==> Nsx=Nsy/rd={ 39.4, 38.5 }
* x line width 230 ns -> 3 dots
* bottom 2.9us red -> 39.15 dots
*
* resolution DPI from image aspect ratio
* Rv=Nv/ly, ly=4in
* ri=Ni/Di, Ni={4,15,16} Di={3,11,9}
* lx=ri*ly
*
* Rh=Nh/lx=Di*(Nh/(Ni*ly))
* ==> ri=4/Di => Nh=k*16
* ri=15/Di => Nh=k*60
* ri=16/Di => Nh=k*64
*
* resolution DPI from dot aspect ratio, general algorithm,
*
* rd=Nd/Dd=ldx/ldy
*
* assume 1 dot = Nd x Dd square subdots at a resolution of k, in dpi, then
*
* ldx=Nd/k, ldy=Dd/k ==> Rh=k/Nd, Rv=k/Dd
*
* choosing k=m*Nd*Dd for integer Rh and Rv gives
*
* ldx=1/(m*Dd), ldy=1/(m*Nd), Rh=m*Dd, Rv=m*Nd
*
* and
*
* lx=Nh*ldx=Nh/(m*Dd), ly=Nv*ldy=Nv/(m*Nd)
*
* so choose m for the intended height Ly, in inch, as
*
* m=round(Nv/(Ly*Nd))
*
* which limits Ly<=Nv/Nd since Rv>=Nd.
*/
//cm=72/2.540005;
real Ly, ly, lx, ysize, xsize, rimage, xd, yd, pwidth;
int Nd, Dd, m, Nh, Nv, Nshift, Na, Nsy;
real fs, Ttone;
Nd=bNdot[bsys];
Dd=bDdot[bsys]*os;
Nh=bNh[bsys]*os;
Nv=bNv[bsys];
Ly=4; // 4 inch vertical size
m=floor(0.5+Nv/(Ly*Nd));
if(m<1) m=1;
ly=Nv/(m*Nd);
lx=Nh/(m*Dd);
ysize=ly*1inch;
xsize=lx*1inch;
rimage=xsize/ysize;
if(verbose > 1)
write('#Nd Dd m ri:\t', Nd, Dd, m, rimage);
//size(xsize,ysize,Aspect); // should not have any effect
Nsy=bNsy[bsys]; // grating size in lines 42,43, 34,35
Nshift=bNsh[bsys]; // shift image up: pre 1997 =3, 2007 =0
fs=1e6*bfs[bsys]*os;
Na=0; // add 1,0,-1 to height of hor center squares for even Na+Nsy
Ttone=fs/250e3; // period of ft=250 kHz, fs/ft=54
real[] ftones={0.8e6/fs, 1.8e6/fs, 2.8e6/fs, 3.8e6/fs, 4.8e6/fs};
xd=xsize/Nh;
yd=ysize/Nv;
pwidth=min(abs(xd),abs(yd));
pen pdefault=squarecap+linewidth(pwidth);
pen pblack=pdefault+gray(0.0);
pen pwhite=pdefault+gray(1.0);
/**** calculate grating repeats and size in tv dots ****/
// horizontal lines
int divsy, rdisty, Nvc, Nt, Nb;
Nvc=floor(Nv/2)-Nshift;
divsy=floor(((Nv-Na-2)/Nsy-1)/2); // (Nv-Na-2)/2-Nsy/2 dots for Nsy lengths
rdisty=Na+Nsy*(1+2*divsy);
Nt=Nvc-ceil(rdisty/2);
Nb=Nv-Nt-rdisty;
if(verbose > 1)
write('#divsy t b: \t',divsy,Nt,Nb);
/* Nsyc: center square height
* line pairing test: verify distance of center to top and bot
* distance is odd ==> top=even/odd, cent=odd/even, bot=even/odd
*
* Nsyc odd: not possible
*
* Nsyc even:
* Nsyc/2 odd --> OK
* Nsyc/2 even --> stagger the raster one line upwards
*
* rcrowt top dist of hor line
* rcrowc true center for color info, distance to top of image.
* rcrowb bot dist of hor line
*
* Nt=Nvc-(offu+divsy*Nsy);
* Nb=Nv-( Nvc-(offd-divsy*Nsy) );
* ==> Nt+Nb=Nv-Nsyc-2*divsy*Nsy
*/
int Nsyc, offu, offd, Nyst=0, i;
int[] rcrowt, rcrowc, rcrowb;
Nsyc=Nsy+Na;
offu=floor(Nsyc/2);
offd=offu-Nsyc;
if(Nsyc%2 != 0) {
Nyst=1;
} else if(Nsyc%4 == 0) {
Nyst=1; /* stagger */
}
for(i=0; i<=divsy; ++i) {
int iu, id, ou, od, ru, rd;
iu=divsy-i;
id=divsy+i+1;
ou=offu+Nsy*i;
od=offd-Nsy*i;
if(verbose > 1)
write(ou,od);
rcrowc[iu]=Nvc-ou;
rcrowc[id]=Nvc-od;
ru=Nvc-(ou+Nyst);
rd=Nvc-(od+Nyst);
rcrowt[iu]=ru-1;
rcrowb[iu]=ru+1;
rcrowt[id]=rd-1;
rcrowb[id]=rd+1;
}
Nt=floor((rcrowt[0]+rcrowb[0])/2);
Nb=Nv-Nt-Nsyc-2*Nsy*divsy;
if(verbose > 1)
write('#st t b: \t',Nyst,Nt,Nb);
/* vertical lines
* (Nh-2*os)/2-Nsx/2 dots available for divisions of Nsx dots.
* At least 5 dots margin left and right ==> use -10*os
*/
real lsq, Nsx;
int divsx, Nhc, Nl;
lsq=Nsy*yd;
Nsx=lsq/xd;
divsx=floor(((Nh-10*os)/Nsx-1)/2);
Nhc=round(Nh/2);
Nl=Nhc-round((1+2*divsx)*Nsx/2);
if(verbose > 1)
write('#Nsx divsx Nl:\t',Nsx,divsx,Nl);
/**** draw gray background ****/
{
path zz;
//zz=tvrect(0,0, Nh,Nv, xd,yd,Nv);
/* keep white canvas for castellations */
zz=tvrect(Nl,Nt, Nh-Nl,Nv-Nb, xd,yd,Nv);
fill(zz, p=pdefault+gray(0.5));
//dot(zz);
}
/**** draw center circle ****/
real cx, cy, crad;
pair ccenter;
path ccirc;
cx=Nh/2;
cy=Nv/2-Nshift;
crad=6*Nsy;
if(Nv%2 != 0) {
crad+=0.5;
}
ccenter=tvps(cx,cy, xd,yd,Nv);
ccirc=circle(ccenter, crad*yd);
if(colortv<=0) {
draw(ccirc, p=pwhite+linewidth(2*yd));
}
/****** draw 2*divsy+2 horizontal lines **********************************/
real[] rcang, rcoff;
pair[] rcright, rcleft;
int i, iend=2*divsy+1;
for(i=0; i<=iend; ++i) {
real y, phi, x;
path zzh;
pair zd;
zzh=tvrect(0,rcrowt[i], Nh,rcrowb[i], xd,yd,Nv);
fill(zzh, p=pwhite);
y=cy-rcrowc[i];
//write(roff);
if(abs(y)<crad) {
phi=asin(y/crad);
} else {
phi=pi/2;
}
rcang[i]=phi;
x=(crad*cos(phi))*yd/xd;
rcoff[i]=x;
zd=tvps(cx+x,cy-y, xd,yd,Nv);
rcright[i]=zd;
//dot(zd);
zd=tvps(cx-x,cy-y, xd,yd,Nv);
rcleft[i]=zd;
}
/****** draw 2*divsx+2 vertical lines ***************************/
int[] coff, coffa, coffb;
int poffa=0, ccenterwhite=divsx%2;
for(i=0; i<=divsx; ++i) {
real cdist=(1+2*i)*Nsx;
int off, offa, offb;
path zzv;
off=round(cdist/2);
//write(cdist,off);
offa=off+os;
offb=off-os;
coff[i]=off;
coffa[i]=offa;
coffb[i]=offb;
//write(Nhc-offa);
zzv=tvrect(Nhc+offb,0, Nhc+offa,Nv, xd,yd,Nv);
fill(zzv, p=pwhite);
zzv=tvrect(Nhc-offa,0, Nhc-offb,Nv, xd,yd,Nv);
fill(zzv, p=pwhite);
/** top castellations, must end with black **/
if(i%2 == ccenterwhite) {
int j, jnum;
if(poffa == 0) {
poffa=-offb;
jnum=1;
} else {
jnum=2;
}
for(j=0; j<jnum; ++j) {
int lc, rc;
path zzc;
if(j==0) {
lc=Nhc+poffa;
rc=Nhc+offb;
} else {
lc=Nhc-offb;
rc=Nhc-poffa;
}
zzc=tvrect(lc,0, rc,Nt-1, xd,yd,Nv);
fill(zzc, p=pblack);
zzc=tvrect(lc,Nv-Nb+1, rc,Nv, xd,yd,Nv);
fill(zzc, p=pblack);
}
}
poffa=offa;
}
//write(coff);
/** left and right castellations **/
/* The bottom right red rectangle tests for a non causal color FIR
* filter in the receiver. The last 2..4 dots then typically appear
* colorless, green, or cyan.
*
* This comes from the fact that the chroma subcarrier is of lower
* bandwidth than luma and thus continues after the last active sample.
* These trailing (y,u,v) samples result from a signal to zero
* transition and depend on the transmit and receive filters. Samples
* from VHS, system B/G/D/K, system I, or a DVD player output are
* different. Nevertheless, a sharpening filter uses this data and so
* adds false color to the last dots.
*/
int lc, rc;
iend=2*divsy+1;
lc=Nhc-coffa[divsx];
rc=Nhc+coffa[divsx];
for(i=1; i<=iend; ++i) {
pen pcast;
if(i == iend && colortv>0) {
pcast=pdefault+rgb(0.75,0.0,0);
} else {
pcast=pblack;
}
if(i%2 == 1) {
int tr, br;
path zzc;
tr=rcrowb[i-1];
br=rcrowt[i];
zzc=tvrect( 0,tr, lc,br, xd,yd,Nv);
fill(zzc, p=pblack);
zzc=tvrect(rc,tr, Nh,br, xd,yd,Nv);
fill(zzc, p=pcast);
}
}
/****** markers for 4/3 aspect ratio ******/
if(rimage>4/3)
rimarkers(rimage, Nh, Nhc, os, Nvc, Nsy, pwhite, xd, yd, Nv);
/****** line pairing center ******/
centerline(coff, coffa, coffb, Nhc, divsx, os, rcrowc, Nvc, divsy,
ccenter, rcoff, rcright, rcleft, pdefault, xd, yd, Nv);
if(colortv>0) {
/* topbw structure */
topbw(coff, Nhc, os, rcrowc[divsy-5], rcrowc[divsy-4], rcrowc[divsy-3],
ccenter, rcleft[divsy-4], rcleft[divsy-3], rcright[divsy-4],
rcright[divsy-3], pdefault, xd, yd, Nv);
/* 250 kHz */
testtone(Ttone, rcrowc[divsy-3], rcrowc[divsy-2],
cx, cy, crad, pdefault, xd, yd, Nv);
/* color bars */
colorbars(coff, Nhc, rcrowc[divsy-2], rcrowc[divsy-1], rcrowc[divsy],
ccenter, rcleft[divsy-2], rcleft[divsy], rcright[divsy-2],
rcright[divsy], pdefault, xd, yd, Nv);
/* test frequencies */
testfreqs(ftones, coff, Nhc, rcrowc[divsy+1], rcrowc[divsy+2],
rcrowc[divsy+3], ccenter, rcleft[divsy+1], rcleft[divsy+3],
rcright[divsy+1],rcright[divsy+3], pdefault, xd, yd, Nv);
/* gray bars */
graybars(coff, Nhc, rcrowc[divsy+3], rcrowc[divsy+4], ccenter,
rcleft[divsy+3], rcleft[divsy+4],
rcright[divsy+3], rcright[divsy+4], pdefault, xd,yd,Nv);
/* PAL ears */
if(colortv==1) {
palears(coff,coffa,coffb, Nhc, rcrowt, rcrowb, Nvc, divsy, -1,
pdefault, xd, yd, Nv);
palears(coff,coffa,coffb, Nhc, rcrowt, rcrowb, Nvc, divsy, 1,
pdefault, xd, yd, Nv);
} else if(colortv==2) {
ntscbars(coff,coffa,coffb, Nhc, rcrowt, rcrowb, Nvc, divsy, -1,
pdefault, xd, yd, Nv);
ntscbars(coff,coffa,coffb, Nhc, rcrowt, rcrowb, Nvc, divsy, 1,
pdefault, xd, yd, Nv);
ntscbars(coff,coffa,coffb, Nhc, rcrowt, rcrowb, Nvc, divsy, -2,
pdefault, xd, yd, Nv);
ntscbars(coff,coffa,coffb, Nhc, rcrowt, rcrowb, Nvc, divsy, 2,
pdefault, xd, yd, Nv);
}
/* bottom wh - black - wh */
bottombw(round((coff[2]+coff[3])/2), Nhc, rcrowc[divsy+4], rcrowc[divsy+5],
ccenter, rcleft[divsy+4], rcleft[divsy+5],
rcright[divsy+4], rcright[divsy+5], pdefault, xd, yd, Nv);
/* bottom yellow red circle */
bottomcirc(coff[0], Nhc, rcrowc[divsy+5], cx, cy, crad,
ccenter, rcleft[divsy+5], rcright[divsy+5], pdefault, xd, yd, Nv);
}
/********************** set id *********************/
{ /* dpi */
pair rpos=tvps(Nhc,round((rcrowc[divsy-4]+rcrowc[divsy-5])/2), xd,yd,Nv);
string iRhor, iRver, ires;
real Rh, Rv;
Rh=Nh/xsize*inch;
Rv=Nv/ysize*inch;
iRhor=format("%.4gx", Rh);
iRver=format("%.4gdpi", Rv);
ires=insert(iRver,0, iRhor);
/* size info */
int rowbot=round((rcrowc[divsy+4]+rcrowc[divsy+5])/2);
pair tpos=tvps(Nhc,rowbot, xd,yd,Nv);
string ihor, iver, itot, iasp, ifm;
real asp, fm;
ihor=format("%ix",Nh);
iver=format("%i ",Nv);
itot=insert(iver,0, ihor);
asp=xsize/ysize;
iasp=format("%.3g ",asp);
fm=fs/1e6;
ifm=format("%.4gMHz",fm);
itot=insert(iasp,0, itot);
itot=insert(ifm,0, itot);
/* size of square */
int rowNsy=round((rcrowc[divsy+5]+rcrowc[divsy+6])/2);
pair Npos=tvps(Nhc+round((coff[4]+coff[5])/2),rowNsy, xd,yd,Nv);
string iNsy=format("%i",Nsy);
pen pbw;
if(colortv>0) {
pbw=pdefault+gray(1.0);
} else {
pbw=pdefault+gray(0.0);
}
label(ires, rpos, p=pbw);
label(itot, tpos, p=pbw);
label(iNsy, Npos, p=pbw);
if(verbose > 1)
write('#res:\t', ires, itot, iNsy);
}
Figure unitcircle.asy
size(0,150);
pair z0=0;
pair z1=1;
real theta=30;
pair z=dir(theta);
draw(circle(z0,1));
filldraw(z0--arc(z0,1,0,theta)--cycle,lightgrey);
dot(z0);
dot(Label,z1);
dot("$(x,y)=(\cos\theta,\sin\theta)$",z);
arrow("area $\frac{\theta}{2}$",dir(0.5*theta),2E);
draw("$\theta$",arc(z0,0.7,0,theta),LeftSide,Arrow,PenMargin);
Figure upint.asy
import graph;
import lowupint;
size(100,0);
real a=-0.8, b=1.2;
real c=-1.0/sqrt(3.0);
partition(a,b,c,max);
arrow("$f(x)$",F(0.5*(a+b)),NNE,red);
label("$\cal{U}$",(0.5*(a+b),f(0.5*(a+b))/2));