diff options
author | Karl Berry <karl@freefriends.org> | 2010-06-08 13:46:05 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2010-06-08 13:46:05 +0000 |
commit | a960e44eb527236f39aec81babc0474911a86078 (patch) | |
tree | 9950eca71791d90820a80a521a7cc252c0955db5 /Build/source/utils/asymptote/base | |
parent | 6443467452320c296faa1f43f0606a9457bd4463 (diff) |
asy 1.96
git-svn-id: svn://tug.org/texlive/trunk@18817 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/base')
-rw-r--r-- | Build/source/utils/asymptote/base/bezulate.asy | 78 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/embed.asy | 4 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/geometry.asy | 2 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/graph3.asy | 155 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/labelpath3.asy | 4 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/lmfit.asy | 28 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/math.asy | 30 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/plain_arrows.asy | 24 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/solids.asy | 5 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/three.asy | 295 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/three_arrows.asy | 2 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/three_light.asy | 17 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/three_surface.asy | 252 | ||||
-rw-r--r-- | Build/source/utils/asymptote/base/three_tube.asy | 223 |
14 files changed, 801 insertions, 318 deletions
diff --git a/Build/source/utils/asymptote/base/bezulate.asy b/Build/source/utils/asymptote/base/bezulate.asy index d935d358989..f3817a47bcf 100644 --- a/Build/source/utils/asymptote/base/bezulate.asy +++ b/Build/source/utils/asymptote/base/bezulate.asy @@ -24,20 +24,20 @@ path[][] containmentTree(path[] paths) bool classified=false; // check if current curve contains or is contained in a group of curves for(int j=0; !classified && j < result.length; ++j) - { - int test = inside(paths[i],result[j][0],zerowinding); - if(test == 1) // current curve contains group's toplevel curve { - // replace toplevel curve with current curve - result[j].insert(0,paths[i]); - classified = true; - } - else if(test == -1) // current curve contained in group's toplevel curve - { - result[j].push(paths[i]); - classified = true; + int test = inside(paths[i],result[j][0],zerowinding); + if(test == 1) // current curve contains group's toplevel curve + { + // replace toplevel curve with current curve + result[j].insert(0,paths[i]); + classified = true; + } + else if(test == -1) // current curve contained in group's toplevel curve + { + result[j].push(paths[i]); + classified = true; + } } - } // create a new group if this curve does not belong to another group if(!classified) result.push(new path[] {paths[i]}); @@ -92,11 +92,11 @@ void connect(path[] paths, path[] result, path[] patch) path[] remainingCurves; path[] inners; for(path[] innerGroup:innerTree) - { - inners.push(innerGroup[0]); - if(innerGroup.length>1) - remainingCurves.append(innerGroup[1:]); - } + { + inners.push(innerGroup[0]); + if(innerGroup.length>1) + remainingCurves.append(innerGroup[1:]); + } connect(remainingCurves,result,patch); real d=2*abs(max(outer)-min(outer)); while(inners.length > 0) { @@ -134,36 +134,36 @@ void connect(path[] paths, path[] result, path[] patch) while(!found && timeoffset > fuzz) { timeoffset /= 2; if(countIntersections(allCurves,start, - point(outer,endtime+timeoffset)) == 2) - { - portion = subpath(outer,endtime,endtime+timeoffset)--start--cycle; - found=true; - // check if an inner curve is inside the portion - for(int k = 0; found && k < inners.length; ++k) + point(outer,endtime+timeoffset)) == 2) { - if(k!=curveIndex && - inside(portion,point(inners[k],0),zerowinding)) - found = false; + portion = subpath(outer,endtime,endtime+timeoffset)--start--cycle; + found=true; + // check if an inner curve is inside the portion + for(int k = 0; found && k < inners.length; ++k) + { + if(k!=curveIndex && + inside(portion,point(inners[k],0),zerowinding)) + found = false; + } } - } } if(!found) timeoffset=-2; while(!found && timeoffset < -fuzz) { timeoffset /= 2; if(countIntersections(allCurves,start, - point(outer,endtime+timeoffset))==2) - { - portion = subpath(outer,endtime+timeoffset,endtime)--start--cycle; - found = true; - // check if an inner curve is inside the portion - for(int k = 0; found && k < inners.length; ++k) + point(outer,endtime+timeoffset))==2) { - if(k!=curveIndex && - inside(portion,point(inners[k],0),zerowinding)) - found = false; + portion = subpath(outer,endtime+timeoffset,endtime)--start--cycle; + found = true; + // check if an inner curve is inside the portion + for(int k = 0; found && k < inners.length; ++k) + { + if(k!=curveIndex && + inside(portion,point(inners[k],0),zerowinding)) + found = false; + } } - } } assert(found); endtime=min(endtime,endtime+timeoffset); @@ -171,8 +171,8 @@ void connect(path[] paths, path[] result, path[] patch) // depends on the curves having opposite orientations path remainder=section(outer,endtime+timeoffset,endtime) - --uncycle(inners[curveIndex], - starttime)--cycle; + --uncycle(inners[curveIndex], + starttime)--cycle; inners.delete(curveIndex); outer = remainder; patch.append(portion); diff --git a/Build/source/utils/asymptote/base/embed.asy b/Build/source/utils/asymptote/base/embed.asy index 504b3af66b0..dc6c7d4101a 100644 --- a/Build/source/utils/asymptote/base/embed.asy +++ b/Build/source/utils/asymptote/base/embed.asy @@ -1,6 +1,6 @@ if(latex()) { -usepackage("hyperref"); -texpreamble("\hypersetup{"+settings.hyperrefOptions+"}"); + usepackage("hyperref"); + texpreamble("\hypersetup{"+settings.hyperrefOptions+"}"); texpreamble(" \ifx\pdfhorigin\undefined% \usepackage[3D,dvipdfmx]{movie15} diff --git a/Build/source/utils/asymptote/base/geometry.asy b/Build/source/utils/asymptote/base/geometry.asy index 8679ada4c75..41a6397de64 100644 --- a/Build/source/utils/asymptote/base/geometry.asy +++ b/Build/source/utils/asymptote/base/geometry.asy @@ -6432,7 +6432,7 @@ point operator *(inversion i, point P) void lineinversion() { - warning("lineinversion","the inversion of the line is not a circle. + warning("lineinversion","the inversion of the line is not a circle. The returned circle has an infinite radius, circle.l has been set."); } diff --git a/Build/source/utils/asymptote/base/graph3.asy b/Build/source/utils/asymptote/base/graph3.asy index 32f66851e75..9c6529a74dd 100644 --- a/Build/source/utils/asymptote/base/graph3.asy +++ b/Build/source/utils/asymptote/base/graph3.asy @@ -59,7 +59,7 @@ void drawtick(picture pic, transform3 T, path3 g, path3 g2, G=(sign == 0) ? locate1.V-Size*locate1.dir--locate1.V+Size*locate1.dir : locate1.V--locate1.V+Size*sign*locate1.dir; - draw(pic,G,p); + draw(pic,G,p,name="tick"); } triple ticklabelshift(triple align, pen p=currentpen) @@ -216,7 +216,10 @@ ticks3 Ticks3(int sign, Label F="", ticklabel ticklabel=null, } else ticklabel=Format(format); } - begingroup3(pic); + bool labelaxis=L.s != "" && primary; + + begingroup3(pic,"axis"); + if(primary) draw(pic,margin(G,p).g,p,arrow); else draw(pic,G,p); @@ -230,8 +233,7 @@ ticks3 Ticks3(int sign, Label F="", ticklabel ticklabel=null, if(val >= a && val <= b) drawtick(pic,t,g,g2,locate,val,size,sign,ptick,extend); } - endgroup3(pic); - + if(N == 0) N=1; if(Size > 0 && primary) { for(int i=(beginlabel ? 0 : 1); @@ -243,8 +245,10 @@ ticks3 Ticks3(int sign, Label F="", ticklabel ticklabel=null, } } } - if(L.s != "" && primary) + if(labelaxis) labelaxis(pic,t,L,G,locate,Sign,ticklabels); + + endgroup3(pic); }; } @@ -1570,8 +1574,8 @@ surface surface(triple[][] f, bool[][] cond={}) for(int j=0; j < ny; ++j) { if(all || (condi[j] && condi[j+1] && condp[j] && condp[j+1])) s.s[++k]=patch(new triple[] {fi[j],fp[j],fp[j+1],fi[j+1]}); - indexi[j]=k; - } + indexi[j]=k; + } } if(count == nx*ny) { @@ -1582,6 +1586,123 @@ surface surface(triple[][] f, bool[][] cond={}) return s; } +surface bispline(real[][] z, real[][] p, real[][] q, real[][] r, + real[] x, real[] y, bool[][] cond={}) +{ // z[i][j] is the value at (x[i],y[j]) + // p and q are the first derivatives with respect to x and y, respectively + // r is the second derivative ddu/dxdy + int n=x.length-1; + int m=y.length-1; + + bool all=cond.length == 0; + + int count; + if(all) + count=n*m; + else { + count=0; + for(int i=0; i < n; ++i) { + bool[] condi=cond[i]; + for(int j=0; j < m; ++j) + if(condi[j]) ++count; + } + } + + surface s=surface(count); + s.index=new int[n][m]; + int k=-1; + for(int i=0; i < n; ++i) { + bool[] condi=all ? null : cond[i]; + real xi=x[i]; + real[] zi=z[i]; + real[] zp=z[i+1]; + real[] ri=r[i]; + real[] rp=r[i+1]; + real[] pi=p[i]; + real[] pp=p[i+1]; + real[] qi=q[i]; + real[] qp=q[i+1]; + real xp=x[i+1]; + real hx=(xp-xi)/3; + int[] indexi=s.index[i]; + for(int j=0; j < m; ++j) { + real yj=y[j]; + real yp=y[j+1]; + if(all || condi[j]) { + triple[][] P=array(4,array(4,O)); + real hy=(yp-yj)/3; + real hxy=hx*hy; + // x and y directions + for(int k=0; k < 4; ++k) { + P[0][k] += xi*X; + P[k][0] += yj*Y; + P[1][k] += (xp+2*xi)/3*X; + P[k][1] += (yp+2*yj)/3*Y; + P[2][k] += (2*xp+xi)/3*X; + P[k][2] += (2*yp+yj)/3*Y; + P[3][k] += xp*X; + P[k][3] += yp*Y; + } + // z: value + P[0][0] += zi[j]*Z; + P[3][0] += zp[j]*Z; + P[0][3] += zi[j+1]*Z; + P[3][3] += zp[j+1]*Z; + // z: first derivative + P[1][0] += (P[0][0].z+hx*pi[j])*Z; + P[1][3] += (P[0][3].z+hx*pi[j+1])*Z; + P[2][0] += (P[3][0].z-hx*pp[j])*Z; + P[2][3] += (P[3][3].z-hx*pp[j+1])*Z; + P[0][1] += (P[0][0].z+hy*qi[j])*Z; + P[3][1] += (P[3][0].z+hy*qp[j])*Z; + P[0][2] += (P[0][3].z-hy*qi[j+1])*Z; + P[3][2] += (P[3][3].z-hy*qp[j+1])*Z; + // z: second derivative + P[1][1] += (P[0][1].z+P[1][0].z-P[0][0].z+hxy*ri[j])*Z; + P[1][2] += (P[0][2].z+P[1][3].z-P[0][3].z-hxy*ri[j+1])*Z; + P[2][1] += (P[2][0].z+P[3][1].z-P[3][0].z-hxy*rp[j])*Z; + P[2][2] += (P[2][3].z+P[3][2].z-P[3][3].z+hxy*rp[j+1])*Z; + s.s[++k]=patch(P); + indexi[j]=k; + } + } + } + + return s; +} + +// return the surface described by a real matrix f, interpolated with +// xsplinetype and ysplinetype. +surface surface(real[][] f, real[] x, real[] y, + splinetype xsplinetype=null, splinetype ysplinetype=xsplinetype, + bool[][] cond={}) +{ + real epsilon=sqrtEpsilon*norm(y); + if(xsplinetype == null) + xsplinetype=(abs(x[0]-x[x.length-1]) <= epsilon) ? periodic : notaknot; + if(ysplinetype == null) + ysplinetype=(abs(y[0]-y[y.length-1]) <= epsilon) ? periodic : notaknot; + int n=x.length; int m=y.length; + real[][] ft=transpose(f); + real[][] tp=new real[m][]; + for(int j=0; j < m; ++j) + tp[j]=xsplinetype(x,ft[j]); + real[][] q=new real[n][]; + for(int i=0; i < n; ++i) + q[i]=ysplinetype(y,f[i]); + real[][] qt=transpose(q); + real[] d1=xsplinetype(x,qt[0]); + real[] d2=xsplinetype(x,qt[m-1]); + real[][] r=new real[n][]; + real[][] p=transpose(tp); + for(int i=0; i < n; ++i) + r[i]=clamped(d1[i],d2[i])(y,p[i]); + surface s=bispline(f,p,q,r,x,y,cond); + if(xsplinetype == periodic) s.ucyclic(true); + if(ysplinetype == periodic) s.vcyclic(true); + return s; +} + // return the surface described by a real matrix f, interpolated with // xsplinetype and ysplinetype. surface surface(real[][] f, pair a, pair b, splinetype xsplinetype, @@ -1730,30 +1851,36 @@ guide3[][] lift(real f(pair z), guide[][] g, interpolate3 join=operator --) } void draw(picture pic=currentpicture, Label[] L=new Label[], - guide3[][] g, pen[] p) + guide3[][] g, pen[] p, light light=currentlight, string name="", + render render=defaultrender, + interaction interaction=LabelInteraction()) { pen thin=is3D() ? thin() : defaultpen; - begingroup3(pic); + if(g.length > 1) + begingroup3(pic,name == "" ? "contours" : name,render); for(int cnt=0; cnt < g.length; ++cnt) { guide3[] gcnt=g[cnt]; pen pcnt=thin+p[cnt]; for(int i=0; i < gcnt.length; ++i) - draw(pic,gcnt[i],pcnt); + draw(pic,gcnt[i],pcnt,light,name); if(L.length > 0) { Label Lcnt=L[cnt]; for(int i=0; i < gcnt.length; ++i) { if(Lcnt.s != "" && size(gcnt[i]) > 1) - label(pic,Lcnt,gcnt[i],pcnt); + label(pic,Lcnt,gcnt[i],pcnt,name,interaction); } } } - endgroup3(pic); + if(g.length > 1) + endgroup3(pic); } void draw(picture pic=currentpicture, Label[] L=new Label[], - guide3[][] g, pen p=currentpen) + guide3[][] g, pen p=currentpen, light light=currentlight, + string name="", interaction interaction=LabelInteraction()) { - draw(pic,L,g,sequence(new pen(int) {return p;},g.length)); + draw(pic,L,g,sequence(new pen(int) {return p;},g.length),light,name, + interaction); } real maxlength(triple f(pair z), pair a, pair b, int nu, int nv) diff --git a/Build/source/utils/asymptote/base/labelpath3.asy b/Build/source/utils/asymptote/base/labelpath3.asy index 8483a76a047..63b2290f1f2 100644 --- a/Build/source/utils/asymptote/base/labelpath3.asy +++ b/Build/source/utils/asymptote/base/labelpath3.asy @@ -48,10 +48,10 @@ surface labelpath(string s, path3 p, real angle=90, triple optional=O) path[] text=texpath(Label(s,(0,0),Align,basealign)); text=scale(1/(max(text).x-min(text).x))*text; path[][] decompose=containmentTree(text); - + real[][] xpos=new real[decompose.length][2]; surface sf; - for(int i=0; i < decompose.length; ++i) {// Identify positions along x-axis + for(int i=0; i < decompose.length; ++i) {// Identify positions along x-axis xpos[i][1]=i; real pos0=0.5(max(decompose[i]).x+min(decompose[i]).x); xpos[i][0]=pos0; diff --git a/Build/source/utils/asymptote/base/lmfit.asy b/Build/source/utils/asymptote/base/lmfit.asy index 72745625824..e70421074e5 100644 --- a/Build/source/utils/asymptote/base/lmfit.asy +++ b/Build/source/utils/asymptote/base/lmfit.asy @@ -28,7 +28,7 @@ the least-squares sum % \begin{equation*} - \sum_{i = 1}^n \left( \frac{y_i - f(a_1, \dots, a_m; x_i)}{\Delta y_i} \right)^2 + \sum_{i = 1}^n \left( \frac{y_i - f(a_1, \dots, a_m; x_i)}{\Delta y_i} \right)^2 \end{equation*} % with respect to the parameters $a_1, \dots, a_m$. @@ -822,13 +822,13 @@ struct FitResult { Fits data points to a function that depends on some parameters. Parameters: - - xdata: Array of x values. - - ydata: Array of y values. - - errors: Array of experimental errors; each element must be strictly positive - - function: Fit function. - - parameters: Parameter array. Before calling fit(), this must contain the initial guesses for the parameters. - Upon return, it will contain the solution parameters. - - control: object of type FitControl that controls various aspects of the fitting procedure. + - xdata: Array of x values. + - ydata: Array of y values. + - errors: Array of experimental errors; each element must be strictly positive + - function: Fit function. + - parameters: Parameter array. Before calling fit(), this must contain the initial guesses for the parameters. + Upon return, it will contain the solution parameters. + - control: object of type FitControl that controls various aspects of the fitting procedure. Returns: An object of type FitResult that conveys information about the fitting process. @@ -865,12 +865,12 @@ FitResult fit(real[] xdata, real[] ydata, real[] errors, real function(real[], r Fits data points to a function that depends on some parameters. Parameters: - - xdata: Array of x values. - - ydata: Array of y values. - - function: Fit function. - - parameters: Parameter array. Before calling fit(), this must contain the initial guesses for the parameters. - Upon return, it will contain the solution parameters. - - control: object of type FitControl that controls various aspects of the fitting procedure. + - xdata: Array of x values. + - ydata: Array of y values. + - function: Fit function. + - parameters: Parameter array. Before calling fit(), this must contain the initial guesses for the parameters. + Upon return, it will contain the solution parameters. + - control: object of type FitControl that controls various aspects of the fitting procedure. Returns: An object of type FitResult that conveys information about the fitting process. diff --git a/Build/source/utils/asymptote/base/math.asy b/Build/source/utils/asymptote/base/math.asy index ff267b955d7..a684307e5a5 100644 --- a/Build/source/utils/asymptote/base/math.asy +++ b/Build/source/utils/asymptote/base/math.asy @@ -144,6 +144,36 @@ int[][] segment(bool[] b) return segment; } +// If the sorted array a does not contain x, insert it sequentially, +// returning the index of x in the resulting array. +int unique(real[] a, real x) { + int i=search(a,x); + if(i == -1 || x != a[i]) { + ++i; + a.insert(i,x); + return i; + } + return i; +} + +int unique(string[] a, string x) { + int i=search(a,x); + if(i == -1 || x != a[i]) { + ++i; + a.insert(i,x); + return i; + } + return i; +} + +bool lexorder(pair a, pair b) { + return a.x < b.x || (a.x == b.x && a.y <= b.y); +} + +bool lexorder(triple a, triple b) { + return a.x < b.x || (a.x == b.x && (a.y < b.y || (a.y == b.y && a.z <= b.z))); +} + real[] zero(int n) { return sequence(new real(int) {return 0;},n); diff --git a/Build/source/utils/asymptote/base/plain_arrows.asy b/Build/source/utils/asymptote/base/plain_arrows.asy index 5284ee9650d..490f76f777c 100644 --- a/Build/source/utils/asymptote/base/plain_arrows.asy +++ b/Build/source/utils/asymptote/base/plain_arrows.asy @@ -546,18 +546,18 @@ void arrow(picture pic=currentpicture, Label L="", pair b, pair dir, // Fit an array of pictures simultaneously using the sizing of picture all. frame[] fit2(picture[] pictures, picture all) { - frame[] out; - if(!all.empty2()) { - transform t=all.calculateTransform(); - pair m=all.min(t); - pair M=all.max(t); - for(picture pic : pictures) { - frame f=pic.fit(t); - draw(f,m,nullpen); - draw(f,M,nullpen); - out.push(f); - } - } + frame[] out; + if(!all.empty2()) { + transform t=all.calculateTransform(); + pair m=all.min(t); + pair M=all.max(t); + for(picture pic : pictures) { + frame f=pic.fit(t); + draw(f,m,nullpen); + draw(f,M,nullpen); + out.push(f); + } + } return out; } diff --git a/Build/source/utils/asymptote/base/solids.asy b/Build/source/utils/asymptote/base/solids.asy index 7e5883bc884..c9be44552c9 100644 --- a/Build/source/utils/asymptote/base/solids.asy +++ b/Build/source/utils/asymptote/base/solids.asy @@ -347,11 +347,12 @@ surface surface(revolution r, int n=nslice, pen color(int i, real j)=null) void draw(picture pic=currentpicture, revolution r, int m=0, int n=nslice, pen frontpen=currentpen, pen backpen=frontpen, pen longitudinalpen=frontpen, pen longitudinalbackpen=backpen, - light light=currentlight, projection P=currentprojection) + light light=currentlight, string name="", + render render=defaultrender, projection P=currentprojection) { pen thin=is3D() ? thin() : defaultpen; skeleton s=r.skeleton(m,n,P); - begingroup3(pic); + begingroup3(pic,name == "" ? "skeleton" : name,render); if(frontpen != nullpen) { draw(pic,s.transverse.back,thin+defaultbackpen+backpen,light); draw(pic,s.transverse.front,thin+frontpen,light); diff --git a/Build/source/utils/asymptote/base/three.asy b/Build/source/utils/asymptote/base/three.asy index 5b3dd26aba7..b0d9c456faa 100644 --- a/Build/source/utils/asymptote/base/three.asy +++ b/Build/source/utils/asymptote/base/three.asy @@ -11,22 +11,78 @@ if(prc0()) { } } +// Useful lossy compression values. +restricted real Zero=0; +restricted real Low=0.0001; +restricted real Medium=0.001; +restricted real High=0.01; + +restricted int PRCsphere=0; // Renders slowly but produces smaller PRC files. +restricted int NURBSsphere=1; // Renders fast but produces larger PRC files. + +struct render +{ + // PRC parameters: + real compression; // lossy compression parameter (0=no compression) + real granularity; // PRC rendering granularity + + bool closed; // use one-sided rendering? + bool tessellate; // use tessellated mesh to store straight patches? + bool3 merge; // merge nodes before rendering, for lower quality + // but faster PRC rendering? + // (default=merge only transparent patches) + int sphere; // PRC sphere type (PRCsphere or NURBSsphere). + + // General parameters: + real margin; // shrink amount for rendered openGL viewport, in bp. + real tubegranularity; // granularity for rendering tubes + + static render defaultrender; + + void operator init(real compression=defaultrender.compression, + real granularity=defaultrender.granularity, + bool closed=defaultrender.closed, + bool tessellate=defaultrender.tessellate, + bool3 merge=defaultrender.merge, + int sphere=defaultrender.sphere, + real margin=defaultrender.margin, + real tubegranularity=defaultrender.tubegranularity) + { + this.compression=compression; + this.granularity=granularity; + this.closed=closed; + this.tessellate=tessellate; + this.merge=merge; + this.sphere=sphere; + this.margin=margin; + this.tubegranularity=tubegranularity; + } +} + +render operator init() {return render();} + +render defaultrender=render.defaultrender=new render; +defaultrender.compression=High; +defaultrender.granularity=Medium; +defaultrender.closed=false; +defaultrender.tessellate=false; +defaultrender.merge=false; +defaultrender.margin=0.02; +defaultrender.tubegranularity=0.005; +defaultrender.sphere=NURBSsphere; + real defaultshininess=0.25; -real defaultgranularity=0; -real linegranularity=0.005; -int linesectors=8; // Number of angular sectors. -real dotgranularity=0.0001; + real angleprecision=1e-5; // Precision for centering perspective projections. int maxangleiterations=25; -real rendermargin=0.02; string defaultembed3Doptions; string defaultembed3Dscript; real defaulteyetoview=63mm/1000mm; -string partname(string s, int i=0) +string partname(int i=0) { - return s == "" ? "" : s+"-"+string(i); + return string(i+1); } triple O=(0,0,0); @@ -733,7 +789,7 @@ struct Controls { // 3D extension of John Hobby's control point formula // (cf. The MetaFont Book, page 131), // as described in John C. Bowman and A. Hammerlindl, - // TUGBOAT: The Communications of th TeX Users Group 29:2 (2008). + // TUGBOAT: The Communications of the TeX Users Group 29:2 (2008). void operator init(triple v0, triple v1, triple d0, triple d1, real tout, real tin, bool atLeast) { @@ -1995,13 +2051,24 @@ path3 plane(triple u, triple v, triple O=O) include three_light; void draw(frame f, path3 g, material p=currentpen, light light=nolight, - string name="", projection P=currentprojection); + string name="", render render=defaultrender, + projection P=currentprojection); + +void begingroup3(frame f, string name="", render render=defaultrender, + triple center=O, int interaction=0) +{ + _begingroup3(f,name,render.compression,render.granularity,render.closed, + render.tessellate,render.merge == false, + render.merge == true,center,interaction); +} -void begingroup3(picture pic=currentpicture, string name="") +void begingroup3(picture pic=currentpicture, string name="", + render render=defaultrender, + triple center=O, int interaction=0) { pic.add(new void(frame f, transform3, picture pic, projection) { if(is3D()) - begingroup(f,name); + begingroup3(f,name,render,center,interaction); if(pic != null) begingroup(pic); },true); @@ -2011,7 +2078,7 @@ void endgroup3(picture pic=currentpicture) { pic.add(new void(frame f, transform3, picture pic, projection) { if(is3D()) - endgroup(f); + endgroup3(f); if(pic != null) endgroup(pic); },true); @@ -2060,13 +2127,14 @@ pair max(frame f, projection P) void draw(picture pic=currentpicture, Label L="", path3 g, align align=NoAlign, material p=currentpen, margin3 margin=NoMargin3, - light light=nolight, string name="") + light light=nolight, string name="", + render render=defaultrender) { pen q=(pen) p; pic.add(new void(frame f, transform3 t, picture pic, projection P) { path3 G=margin(t*g,q).g; if(is3D()) { - draw(f,G,p,light,name,null); + draw(f,G,p,light,name,render,null); if(pic != null && size(G) > 0) pic.addBox(min(G,P),max(G,P),min(q),max(q)); } @@ -2086,45 +2154,91 @@ include three_tube; draw=new void(frame f, path3 g, material p=currentpen, light light=nolight, string name="", + render render=defaultrender, projection P=currentprojection) { pen q=(pen) p; if(is3D()) { - p=material(p,(p.granularity >= 0) ? p.granularity : linegranularity); + p=material(p); void drawthick(path3 g) { if(settings.thick) { real width=linewidth(q); if(width > 0) { - tube T=tube(g,width,linesectors); + bool prc=prc(); + void cylinder(transform3) {}; + void sphere(transform3, bool half) {}; + void disk(transform3) {}; + void tube(path3, path3); + if(prc) { + cylinder=new void(transform3 t) {drawPRCcylinder(f,t,p,light);}; + sphere=new void(transform3 t, bool half) + {drawPRCsphere(f,t,half,p,light,render);}; + disk=new void(transform3 t) {draw(f,t*unitdisk,p,light);}; + tube=new void(path3 center, path3 g) + {drawPRCtube(f,center,g,p,light);}; + } + real linecap; + real r; + bool open=!cyclic(g); int L=length(g); + triple g0,gL; + if(open && L > 0) { + g0=point(g,0); + gL=point(g,L); + linecap=linecap(q); + r=0.5*width; + if(linecap == 2) { + g0 -= r*dir(g,0); + gL += r*dir(g,L); + g=g0..g..gL; + L += 2; + } + } + tube T=tube(g,width,render,cylinder,sphere,tube); + path3 c=T.center; if(L >= 0) { - if(!cyclic(g)) { - real r=0.5*width; - real linecap=linecap(q); - transform3 scale3r=scale3(r); - surface cap; - triple dirL=dir(g,L); + if(open) { + int Lc=length(c); + triple c0=point(c,0); + triple cL=point(c,Lc); triple dir0=dir(g,0); - if(linecap == 0) - cap=scale(r,r,1)*unitdisk; - else if(linecap == 1) - cap=scale3r*((dir0 == O || dirL == O) ? - unitsphere : unithemisphere); - else if(linecap == 2) { - cap=scale3r*unitcylinder; - cap.append(scale3r*shift(Z)*unitdisk); + triple dirL=dir(g,L); + triple dirc0=dir(c,0); + triple dircL=dir(c,Lc); + transform3 t0=shift(g0)*align(-dir0); + transform3 tL=shift(gL)*align(dirL); + transform3 tc0=shift(c0)*align(-dirc0); + transform3 tcL=shift(cL)*align(dircL); + if(linecap == 0 || linecap == 2){ + transform3 scale2r=scale(r,r,1); + T.s.append(t0*scale2r*unitdisk); + disk(tc0*scale2r); + if(L > 0) { + T.s.append(tL*scale2r*unitdisk); + disk(tcL*scale2r); + } + } else if(linecap == 1) { + transform3 scale3r=scale3(r); + T.s.append(t0*scale3r* + (dir0 != O ? unithemisphere : unitsphere)); + sphere(tc0*scale3r,half=straight(c,0)); + if(L > 0) { + T.s.append(tL*scale3r* + (dirL != O ? unithemisphere : unitsphere)); + sphere(tcL*scale3r,half=straight(c,Lc-1)); + } } - T.s.append(shift(point(g,0))*align(-dir0)*cap); - T.s.append(shift(point(g,L))*align(dirL)*cap); } if(opacity(q) == 1) - _draw(f,T.center,q,name); + _draw(f,c,q); } - for(int i=0; i < T.s.s.length; ++i) - draw3D(f,T.s.s[i],p,light,partname(name,i)); - } else _draw(f,g,q,name); - } else _draw(f,g,q,name); + for(patch s : T.s.s) + draw3D(f,s,p,light,prc=false); + } else _draw(f,g,q); + } else _draw(f,g,q); } real[] dash=linetype(adjust(q,arclength(g),cyclic(g))); + if(q != nullpen) + begingroup3(f,name == "" ? "curve" : name,render); if(dash.length == 0) drawthick(g); else { if(sum(dash) > 0) { @@ -2144,22 +2258,33 @@ draw=new void(frame f, path3 g, material p=currentpen, } } } + if(q != nullpen) + endgroup3(f); } else draw(f,project(g,P),q); }; void draw(frame f, explicit path3[] g, material p=currentpen, - light light=nolight, string name="", projection P=currentprojection) + light light=nolight, string name="", + render render=defaultrender, projection P=currentprojection) { + if(g.length > 1) + begingroup3(f,name == "" ? "curve" : name,render); for(int i=0; i < g.length; ++i) - draw(f,g[i],p,light,partname(name,i),P); + draw(f,g[i],p,light,partname(i),render,P); + if(g.length > 1) + endgroup3(f); } void draw(picture pic=currentpicture, explicit path3[] g, material p=currentpen, margin3 margin=NoMargin3, light light=nolight, - string name="") + string name="", render render=defaultrender) { + if(g.length > 1) + begingroup3(pic,name == "" ? "curves" : name,render); for(int i=0; i < g.length; ++i) - draw(pic,g[i],p,margin,light,partname(name,i)); + draw(pic,g[i],p,margin,light,partname(i),render); + if(g.length > 1) + endgroup3(pic); } include three_arrows; @@ -2167,24 +2292,34 @@ include three_arrows; void draw(picture pic=currentpicture, Label L="", path3 g, align align=NoAlign, material p=currentpen, arrowbar3 arrow, arrowbar3 bar=None, margin3 margin=NoMargin3, light light=nolight, - light arrowheadlight=currentlight, string name="") + light arrowheadlight=currentlight, string name="", + render render=defaultrender) { - begingroup3(pic); + bool group=arrow != None || bar != None; + if(group) + begingroup3(pic,name,render); bool drawpath=arrow(pic,g,p,margin,light,arrowheadlight); if(bar(pic,g,p,margin,light,arrowheadlight) && drawpath) - draw(pic,L,g,align,p,margin,light,name); - endgroup3(pic); + draw(pic,L,g,align,p,margin,light); + if(group) + endgroup3(pic); label(pic,L,g,align,(pen) p); } void draw(frame f, path3 g, material p=currentpen, arrowbar3 arrow, light light=nolight, light arrowheadlight=currentlight, - string name="", projection P=currentprojection) + string name="", render render=defaultrender, + projection P=currentprojection) { picture pic; + bool group=arrow != None; + if(group) + begingroup3(f,name,render); if(arrow(pic,g,p,NoMargin3,light,arrowheadlight)) - draw(f,g,p,light,name,P); + draw(f,g,p,light,P); add(f,pic.fit()); + if(group) + endgroup3(f); } void add(picture pic=currentpicture, void d(picture,transform3), @@ -2300,14 +2435,38 @@ private struct viewpoint { triple target,camera,up; real angle; void operator init(string s) { - s=replace(s,new string[][] {{" ",","},{"}{",","},{"{",""},{"}",""},}); - string[] S=split(s,","); - target=((real) S[0],(real) S[1],(real) S[2])*cm; - camera=target+(real) S[6]*((real) S[3],(real) S[4],(real) S[5])*cm; + s=replace(s,'\n'," "); + string[] S=split(s); + int pos(string s, string key) { + int pos=find(s,key); + if(pos < 0) return -1; + pos += length(key); + while(substr(s,pos,1) == " ") ++pos; + if(substr(s,pos,1) == "=") + return pos+1; + return -1; + } + triple C2C=X; + real ROO=1; + real ROLL=0; + angle=30; + int pos; + for(int k=0; k < S.length; ++k) { + if((pos=pos(S[k],"COO")) >= 0) + target=((real) substr(S[k],pos),(real) S[++k],(real) S[++k]); + else if((pos=pos(S[k],"C2C")) >= 0) + C2C=((real) substr(S[k],pos),(real) S[++k],(real) S[++k]); + else if((pos=pos(S[k],"ROO")) >= 0) + ROO=(real) substr(S[k],pos); + else if((pos=pos(S[k],"ROLL")) >= 0) + ROLL=(real) substr(S[k],pos); + else if((pos=pos(S[k],"AAC")) >= 0) + angle=(real) substr(S[k],pos); + } + camera=target+ROO*C2C; triple u=unit(target-camera); triple w=unit(Z-u.z*u); - up=rotate((real) S[7],O,u)*w; - angle=S[8] == "" ? 30 : (real) S[8]; + up=rotate(ROLL,O,u)*w; } } @@ -2393,13 +2552,13 @@ private string billboard(int[] index, triple[] center) if(index.length == 0) return ""; string s=" var zero=new Vector3(0,0,0); -var meshes=scene.meshes; -var count=meshes.count; +var nodes=scene.nodes; +var count=nodes.count; var index=new Array(); for(i=0; i < count; i++) { - var mesh=meshes.getByIndex(i); - var name=mesh.name; + var node=nodes.getByIndex(i); + var name=node.name; end=name.lastIndexOf(\".\")-1; if(end > 0) { if(name.substr(end,1) == \"\001\") { @@ -2407,7 +2566,7 @@ for(i=0; i < count; i++) { n=end-start; if(n > 0) { index[name.substr(start,n)]=i; - mesh.name=name.substr(0,start-1); + node.name=name.substr(0,start-1); } } } @@ -2416,7 +2575,7 @@ for(i=0; i < count; i++) { var center=new Array( "; for(int i=0; i < center.length; ++i) - s += "Vector3("+format(center[i]/cm,",")+"), + s += "Vector3("+format(center[i],",")+"), "; s += "); @@ -2431,12 +2590,12 @@ billboardHandler.onEvent=function(event) function f(i,k) { j=index[i]; if(j >= 0) { - var mesh=meshes.getByIndex(j); - var name=mesh.name; + var node=nodes.getByIndex(j); + var name=node.name; var R=Matrix4x4(); R.setView(zero,direction,up); var c=center[k]; - var T=mesh.transform; + var T=node.transform; T.setIdentity(); T.translateInPlace(c.scale(-1)); T.multiplyInPlace(R); @@ -2513,13 +2672,13 @@ string embed3D(string label="", string text=label, string prefix, if(script == "") script=defaultembed3Dscript; // Adobe Reader doesn't appear to support user-specified viewport lights. - string lightscript=light.on() && !light.viewport ? lightscript(light) : ""; + string lightscript=light.on() && light.viewport ? "" : lightscript(light); real viewplanesize; if(P.infinity) { triple lambda=max3(f)-min3(f); pair margin=viewportmargin((lambda.x,lambda.y)); - viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/(cm*P.zoom); + viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/P.zoom; } else if(!P.absolute) P.angle=2*aTan(Tan(0.5*P.angle)); @@ -2542,7 +2701,7 @@ string embed3D(string label="", string text=label, string prefix, P.viewportshift.y*lambda.y/P.zoom,0); } - triple v=P.vector()/cm; + triple v=P.vector(); triple u=unit(v); triple w=Z-u.z*u; real roll; @@ -2560,7 +2719,7 @@ string embed3D(string label="", string text=label, string prefix, ",toolbar="+(settings.toolbar ? "true" : "false")+ ",3Daac="+Format(P.angle)+ ",3Dc2c="+Format(u)+ - ",3Dcoo="+Format(target/cm)+ + ",3Dcoo="+Format(target)+ ",3Droll="+Format(roll)+ ",3Droo="+Format(abs(v))+ ",3Dbg="+Format(light.background()); @@ -2613,7 +2772,7 @@ struct scene if(this.P.center && settings.render != 0) { triple target=0.5*(m+M); this.P.target=target; - this.P.calculate(); + this.P.calculate(); } if(this.P.autoadjust || this.P.infinity) adjusted=adjusted | this.P.adjust(m,M); @@ -2796,7 +2955,7 @@ object embed(string label="", string text=label, string prefix=defaultfilename, } else if(M.z >= 0) abort("camera too close"); shipout3(prefix,f,preview ? nativeformat() : format, - S.width-rendermargin,S.height-rendermargin, + S.width-defaultrender.margin,S.height-defaultrender.margin, P.infinity ? 0 : 2aTan(Tan(0.5*P.angle)*P.zoom), P.zoom,m,M,P.viewportshift, tinv*inverse(modelview)*shift(0,0,zcenter),light.background(), diff --git a/Build/source/utils/asymptote/base/three_arrows.asy b/Build/source/utils/asymptote/base/three_arrows.asy index b4319219284..d81650ec948 100644 --- a/Build/source/utils/asymptote/base/three_arrows.asy +++ b/Build/source/utils/asymptote/base/three_arrows.asy @@ -106,7 +106,7 @@ struct arrowhead3 } if(draw) for(path3 g : H) - s.append(tube(g,width,linesectors).s); + s.append(tube(g,width).s); return shift(v)*s; } diff --git a/Build/source/utils/asymptote/base/three_light.asy b/Build/source/utils/asymptote/base/three_light.asy index 36ba9a34c19..eb85ed0c3e5 100644 --- a/Build/source/utils/asymptote/base/three_light.asy +++ b/Build/source/utils/asymptote/base/three_light.asy @@ -2,27 +2,24 @@ struct material { pen[] p; // diffusepen,ambientpen,emissivepen,specularpen real opacity; real shininess; - real granularity; void operator init(pen diffusepen=black, pen ambientpen=black, pen emissivepen=black, pen specularpen=mediumgray, real opacity=opacity(diffusepen), - real shininess=defaultshininess, - real granularity=-1) { + real shininess=defaultshininess) { p=new pen[] {diffusepen,ambientpen,emissivepen,specularpen}; this.opacity=opacity; this.shininess=shininess; - this.granularity=granularity; } - void operator init(material m, real granularity=m.granularity) { + void operator init(material m) { p=copy(m.p); opacity=m.opacity; shininess=m.shininess; - this.granularity=granularity; } pen diffuse() {return p[0];} pen ambient() {return p[1];} pen emissive() {return p[2];} pen specular() {return p[3];} + void diffuse(pen q) {p[0]=q;} void ambient(pen q) {p[1]=q;} void emissive(pen q) {p[2]=q;} @@ -39,7 +36,6 @@ void write(file file, string s="", material x, suffix suffix=none) write(file,", specular=",x.specular()); write(file,", opacity=",x.opacity); write(file,", shininess=",x.shininess); - write(file,", granularity=",x.granularity); write(file,"}",suffix); } @@ -51,7 +47,7 @@ void write(string s="", material x, suffix suffix=endl) bool operator == (material m, material n) { return all(m.p == n.p) && m.opacity == n.opacity && - m.shininess == n.shininess && m.granularity == n.granularity; + m.shininess == n.shininess; } material operator cast(pen p) @@ -69,10 +65,9 @@ pen operator ecast(material m) return m.p.length > 0 ? m.diffuse() : nullpen; } -material emissive(material m, real granularity=m.granularity) +material emissive(material m) { - return material(black+opacity(m.opacity),black,m.diffuse(),black,m.opacity,1, - granularity); + return material(black+opacity(m.opacity),black,m.diffuse(),black,m.opacity,1); } pen color(triple normal, material m, light light, transform3 T=light.T) { diff --git a/Build/source/utils/asymptote/base/three_surface.asy b/Build/source/utils/asymptote/base/three_surface.asy index 1be7eb0259c..e00acfa8367 100644 --- a/Build/source/utils/asymptote/base/three_surface.asy +++ b/Build/source/utils/asymptote/base/three_surface.asy @@ -4,6 +4,8 @@ private import interpolate; int nslice=12; real camerafactor=1.2; +string meshname(string name) {return name+" mesh";} + private real Fuzz=10.0*realEpsilon; private real nineth=1/9; @@ -1148,22 +1150,53 @@ interaction LabelInteraction() return settings.autobillboard ? Billboard : Embedded; } -void draw3D(frame f, patch s, triple center=O, material m, - light light=currentlight, string name="", - interaction interaction=Embedded) +private material material(material m, light light) +{ + return light.on() || invisible((pen) m) ? m : emissive(m); +} + +void draw3D(frame f, int type=0, patch s, triple center=O, material m, + light light=currentlight, interaction interaction=Embedded, + bool prc=true) { if(s.colors.length > 0) m=mean(s.colors); - bool lighton=light.on(); - if(!lighton && !invisible((pen) m)) - m=emissive(m); + m=material(m,light); real PRCshininess; if(prc()) PRCshininess=PRCshininess(m.shininess); - real granularity=m.granularity >= 0 ? m.granularity : defaultgranularity; + draw(f,s.P,center,s.straight,m.p,m.opacity,m.shininess,PRCshininess, - granularity,s.planar ? s.normal(0.5,0.5) : O,s.colors,lighton,name, - interaction.type); + s.planar ? s.normal(0.5,0.5) : O,s.colors, + light.on(),interaction.type,prc); +} + +void drawPRCsphere(frame f, transform3 t=identity4, bool half=false, material m, + light light=currentlight, render render=defaultrender) +{ + m=material(m,light); + drawPRCsphere(f,t,half,m.p,m.opacity,PRCshininess(m.shininess),render.sphere); +} + +void drawPRCcylinder(frame f, transform3 t=identity4, material m, + light light=currentlight) +{ + m=material(m,light); + drawPRCcylinder(f,t,m.p,m.opacity,PRCshininess(m.shininess)); +} + +void drawPRCdisk(frame f, transform3 t=identity4, material m, + light light=currentlight) +{ + m=material(m,light); + drawPRCdisk(f,t,m.p,m.opacity,PRCshininess(m.shininess)); +} + +void drawPRCtube(frame f, path3 center, path3 g, material m, + light light=currentlight) +{ + m=material(m,light); + drawPRCtube(f,center,g,m.p,m.opacity,PRCshininess(m.shininess)); } void tensorshade(transform t=identity(), frame f, patch s, @@ -1180,22 +1213,28 @@ nullpens.cyclic=true; void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, material[] surfacepen, pen[] meshpen=nullpens, light light=currentlight, light meshlight=light, string name="", - projection P=currentprojection) + render render=defaultrender, projection P=currentprojection) { if(is3D()) { + begingroup3(f,name == "" ? "surface" : name,render); for(int i=0; i < s.s.length; ++i) - draw3D(f,s.s[i],surfacepen[i],light,partname(name,i)); + draw3D(f,s.s[i],surfacepen[i],light); + endgroup3(f); pen modifiers=thin()+squarecap; for(int k=0; k < s.s.length; ++k) { pen meshpen=meshpen[k]; if(!invisible(meshpen)) { + begingroup3(f,meshname(name),render); meshpen=modifiers+meshpen; real step=nu == 0 ? 0 : 1/nu; for(int i=0; i <= nu; ++i) - draw(f,s.s[k].uequals(i*step),meshpen,meshlight); + draw(f,s.s[k].uequals(i*step),meshpen,meshlight,partname(i), + render); step=nv == 0 ? 0 : 1/nv; for(int j=0; j <= nv; ++j) - draw(f,s.s[k].vequals(j*step),meshpen,meshlight); + draw(f,s.s[k].vequals(j*step),meshpen,meshlight,partname(j), + render); + endgroup3(f); } } } else { @@ -1232,18 +1271,19 @@ void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, material surfacepen=currentpen, pen meshpen=nullpen, light light=currentlight, light meshlight=light, string name="", - projection P=currentprojection) + render render=defaultrender, projection P=currentprojection) { material[] surfacepen={surfacepen}; pen[] meshpen={meshpen}; surfacepen.cyclic=true; meshpen.cyclic=true; - draw(t,f,s,nu,nv,surfacepen,meshpen,light,meshlight,name,P); + draw(t,f,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render,P); } void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen[] meshpen=nullpens, - light light=currentlight, light meshlight=light, string name="") + light light=currentlight, light meshlight=light, string name="", + render render=defaultrender) { if(s.empty()) return; @@ -1257,7 +1297,7 @@ void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, pic.add(new void(frame f, transform3 t, picture pic, projection P) { surface S=t*s; if(is3D()) - draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name); + draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name,render); else if(pic != null) pic.add(new void(frame f, transform T) { draw(T,f,S,nu,nv,surfacepen,meshpen,light,meshlight,P); @@ -1288,22 +1328,24 @@ void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material surfacepen=currentpen, pen meshpen=nullpen, - light light=currentlight, light meshlight=light, string name="") + light light=currentlight, light meshlight=light, string name="", + render render=defaultrender) { material[] surfacepen={surfacepen}; pen[] meshpen={meshpen}; surfacepen.cyclic=true; meshpen.cyclic=true; - draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name); + draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render); } void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1, material[] surfacepen, pen meshpen, - light light=currentlight, light meshlight=light, string name="") + light light=currentlight, light meshlight=light, string name="", + render render=defaultrender) { pen[] meshpen={meshpen}; meshpen.cyclic=true; - draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name); + draw(pic,s,nu,nv,surfacepen,meshpen,light,meshlight,name,render); } surface extrude(path3 p, path3 q) @@ -1376,7 +1418,8 @@ private path[] path(Label L, pair z=0, projection P) void label(frame f, Label L, triple position, align align=NoAlign, pen p=currentpen, light light=nolight, - string name=L.s, interaction interaction=LabelInteraction(), + string name="", render render=defaultrender, + interaction interaction=LabelInteraction(), projection P=currentprojection) { Label L=L.copy(); @@ -1386,10 +1429,10 @@ void label(frame f, Label L, triple position, align align=NoAlign, L.T=L.T*scale(abs(P.camera-position)/abs(P.vector())); if(L.defaulttransform3) L.T3=transform3(P); + begingroup3(f,name == "" ? L.s : name,render); if(is3D()) { - int i=-1; for(patch S : surface(L,position).s) - draw3D(f,S,position,L.p,light,partname(name,++i),interaction); + draw3D(f,S,position,L.p,light,interaction); } else { pen p=color(L.T3*Z,L.p,light,shiftless(P.T.modelview)); if(L.defaulttransform3) { @@ -1404,11 +1447,13 @@ void label(frame f, Label L, triple position, align align=NoAlign, for(patch S : surface(L,position).s) fill(f,project(S.external(),P,1),p); } + endgroup3(f); } void label(picture pic=currentpicture, Label L, triple position, align align=NoAlign, pen p=currentpen, - light light=nolight, string name=L.s, + light light=nolight, string name="", + render render=defaultrender, interaction interaction=LabelInteraction()) { Label L=L.copy(); @@ -1421,18 +1466,18 @@ void label(picture pic=currentpicture, Label L, triple position, triple v=t*position; if(!align.is3D && L.align.relative && L.align.dir3 != O && determinant(P.t) != 0) - L.align(L.align.dir*unit(project(v+L.align.dir3,P.t)-project(v,P.t))); + L.align(L.align.dir*unit(project(v+L.align.dir3,P.t)-project(v,P.t))); if(interaction.targetsize && settings.render != 0) L.T=L.T*scale(abs(P.camera-v)/abs(P.vector())); if(L.defaulttransform3) L.T3=transform3(P); - if(is3D()) { - int i=-1; + surface S=surface(L,v); + begingroup3(f,name == "" ? L.s : name,render,v,interaction.type); + if(is3D()) for(patch S : surface(L,v).s) - draw3D(f,S,v,L.p,light,partname(name,++i),interaction); - } + draw3D(f,S,v,L.p,light,interaction); if(pic != null) { pen p=color(L.T3*Z,L.p,light,shiftless(P.T.modelview)); @@ -1450,6 +1495,7 @@ void label(picture pic=currentpicture, Label L, triple position, fill(f,T*project(S.external(),P,1),p); }); } + endgroup3(f); },!L.defaulttransform3); @@ -1467,7 +1513,7 @@ void label(picture pic=currentpicture, Label L, triple position, } void label(picture pic=currentpicture, Label L, path3 g, align align=NoAlign, - pen p=currentpen, string name=L.s, + pen p=currentpen, light light=nolight, string name="", interaction interaction=LabelInteraction()) { Label L=L.copy(); @@ -1480,11 +1526,11 @@ void label(picture pic=currentpicture, Label L, path3 g, align align=NoAlign, if(L.align.default) { align a; a.init(-I*(position <= sqrtEpsilon ? S : - position >= length(g)-sqrtEpsilon ? N : E),relative=true); + position >= length(g)-sqrtEpsilon ? N : E),relative=true); a.dir3=dir(g,position); // Pass 3D direction via unused field. L.align(a); } - label(pic,L,point(g,position),name,interaction); + label(pic,L,point(g,position),light,name,interaction); } surface extrude(Label L, triple axis=Z) @@ -1609,67 +1655,143 @@ restricted surface unitplane=surface(unitplane); restricted surface unitdisk=surface(unitcircle3); void dot(frame f, triple v, material p=currentpen, - light light=nolight, string name="", projection P=currentprojection) + light light=nolight, string name="", + render render=defaultrender, projection P=currentprojection) { pen q=(pen) p; if(is3D()) { - material m=material(p,p.granularity >= 0 ? p.granularity : dotgranularity); - int i=-1; + begingroup3(f,name == "" ? "dot" : name,render); + real size=0.5*linewidth(dotsize(q)+q); + transform3 T=shift(v)*scale3(size); for(patch s : unitsphere.s) - draw3D(f,shift(v)*scale3(0.5*linewidth(dotsize(q)+q))*s,m,light, - partname(name,++i)); + draw3D(f,T*s,v,p,light,prc=false); + if(prc()) + drawPRCsphere(f,T,p,light); + endgroup3(f); } else dot(f,project(v,P.t),q); } -void dot(frame f, path3 g, material p=currentpen, +void dot(frame f, triple[] v, material p=currentpen, light light=nolight, + string name="", render render=defaultrender, + projection P=currentprojection) +{ + if(v.length > 0) { + // Remove duplicate points. + v=sort(v,lexorder); + + triple last=v[0]; + dot(f,last,p,light,name,P); + for(int i=1; i < v.length; ++i) { + triple V=v[i]; + if(V != last) { + dot(f,V,p,light,name,render,P); + last=V; + } + } + } +} + +void dot(frame f, path3 g, material p=currentpen, light light=nolight, + string name="", render render=defaultrender, projection P=currentprojection) { - for(int i=0; i <= length(g); ++i) dot(f,point(g,i),p,P); + dot(f,sequence(new triple(int i) {return point(g,i);},size(g)), + p,light,name,render,P); } -void dot(frame f, path3[] g, material p=currentpen, +void dot(frame f, path3[] g, material p=currentpen, light light=nolight, + string name="", render render=defaultrender, projection P=currentprojection) { - for(int i=0; i < g.length; ++i) dot(f,g[i],p,P); + int sum; + for(path3 G : g) + sum += size(G); + int i,j; + dot(f,sequence(new triple(int) { + while(j >= size(g[i])) { + ++i; + j=0; + } + triple v=point(g[i],j); + ++j; + return v; + },sum),p,light,name,render,P); } void dot(picture pic=currentpicture, triple v, material p=currentpen, - light light=nolight, string name="") + light light=nolight, string name="", render render=defaultrender) { pen q=(pen) p; real size=0.5*linewidth(dotsize(q)+q); pic.add(new void(frame f, transform3 t, picture pic, projection P) { + triple V=t*v; if(is3D()) { - material m=material(p,p.granularity >= 0 ? p.granularity : - dotgranularity); - int i=-1; + begingroup3(f,name == "" ? "dot" : name,render); + transform3 T=shift(V)*scale3(size); for(patch s : unitsphere.s) - draw3D(f,shift(t*v)*scale3(size)*s,m,light,partname(name,++i)); + draw3D(f,T*s,V,p,light,prc=false); + if(prc()) + drawPRCsphere(f,T,p,light,render); + endgroup3(f); } if(pic != null) - dot(pic,project(t*v,P.t),q); + dot(pic,project(V,P.t),q); },true); triple R=size*(1,1,1); pic.addBox(v,v,-R,R); } -void dot(picture pic=currentpicture, triple[] v, material p=currentpen) +void dot(picture pic=currentpicture, triple[] v, material p=currentpen, + light light=nolight, string name="", render render=defaultrender) { - for(int i=0; i < v.length; ++i) dot(pic,v[i],p); + if(v.length > 0) { + // Remove duplicate points. + v=sort(v,lexorder); + + triple last=v[0]; + begingroup3(pic,name == "" ? "dots" : name,render); + dot(pic,last,p,light,partname(0),render); + int k=0; + for(int i=1; i < v.length; ++i) { + triple V=v[i]; + if(V != last) { + dot(pic,V,p,light,partname(++k),render); + last=V; + } + } + endgroup3(pic); + } } -void dot(picture pic=currentpicture, explicit path3 g, material p=currentpen) +void dot(picture pic=currentpicture, explicit path3 g, material p=currentpen, + light light=nolight, string name="", + render render=defaultrender) { - for(int i=0; i <= length(g); ++i) dot(pic,point(g,i),p); + dot(pic,sequence(new triple(int i) {return point(g,i);},size(g)), + p,light,name,render); } -void dot(picture pic=currentpicture, path3[] g, material p=currentpen) +void dot(picture pic=currentpicture, path3[] g, material p=currentpen, + light light=nolight, string name="", render render=defaultrender) { - for(int i=0; i < g.length; ++i) dot(pic,g[i],p); + int sum; + for(path3 G : g) + sum += size(G); + int i,j; + dot(pic,sequence(new triple(int) { + while(j >= size(g[i])) { + ++i; + j=0; + } + triple v=point(g[i],j); + ++j; + return v; + },sum),p,light,name,render); } void dot(picture pic=currentpicture, Label L, triple v, align align=NoAlign, - string format=defaultformat, material p=currentpen) + string format=defaultformat, material p=currentpen, + light light=nolight, string name="", render render=defaultrender) { Label L=L.copy(); if(L.s == "") { @@ -1679,8 +1801,8 @@ void dot(picture pic=currentpicture, Label L, triple v, align align=NoAlign, } L.align(align,E); L.p((pen) p); - dot(pic,v,p); - label(pic,L,v); + dot(pic,v,p,light,name,render); + label(pic,L,v,render); } pair minbound(triple[] A, projection P) @@ -1734,7 +1856,8 @@ triple[][] operator / (triple[][] a, real[][] b) // Draw a NURBS curve. void draw(picture pic=currentpicture, triple[] P, real[] knot, - real[] weights=new real[], pen p=currentpen, string name="") + real[] weights=new real[], pen p=currentpen, string name="", + render render=defaultrender) { P=copy(P); knot=copy(knot); @@ -1742,7 +1865,9 @@ void draw(picture pic=currentpicture, triple[] P, real[] knot, pic.add(new void(frame f, transform3 t, picture pic, projection Q) { if(is3D()) { triple[] P=t*P; - draw(f,P,knot,weights,p,name); + begingroup3(f,name == "" ? "curve" : name,render); + draw(f,P,knot,weights,p); + endgroup3(f); if(pic != null) pic.addBox(minbound(P,Q),maxbound(P,Q)); } @@ -1753,7 +1878,8 @@ void draw(picture pic=currentpicture, triple[] P, real[] knot, // Draw a NURBS surface. void draw(picture pic=currentpicture, triple[][] P, real[] uknot, real[] vknot, real[][] weights=new real[][], material m=currentpen, - pen[] colors=new pen[], light light=currentlight, string name="") + pen[] colors=new pen[], light light=currentlight, string name="", + render render=defaultrender) { if(colors.length > 0) m=mean(colors); @@ -1765,14 +1891,14 @@ void draw(picture pic=currentpicture, triple[][] P, real[] uknot, real[] vknot, colors=copy(colors); pic.add(new void(frame f, transform3 t, picture pic, projection Q) { if(is3D()) { + begingroup3(f,name == "" ? "surface" : name,render); triple[][] P=t*P; - real granularity=m.granularity >= 0 ? m.granularity : - defaultgranularity; real PRCshininess; if(prc()) PRCshininess=PRCshininess(m.shininess); draw(f,P,uknot,vknot,weights,m.p,m.opacity,m.shininess,PRCshininess, - granularity,colors,lighton,name); + colors,lighton); + endgroup3(f); if(pic != null) pic.addBox(minbound(P,Q),maxbound(P,Q)); } diff --git a/Build/source/utils/asymptote/base/three_tube.asy b/Build/source/utils/asymptote/base/three_tube.asy index c79ae3f619f..2eb5e4cf716 100644 --- a/Build/source/utils/asymptote/base/three_tube.asy +++ b/Build/source/utils/asymptote/base/three_tube.asy @@ -1,5 +1,6 @@ -void render(path3 s, real granularity=linegranularity, void f(path3, real)) +void render(path3 s, void f(path3, real), render render=defaultrender) { + real granularity=render.tubegranularity; void Split(triple z0, triple c0, triple c1, triple z1, real t0=0, real t1=1, real depth=mantissaBits) { if(depth > 0) { @@ -65,8 +66,8 @@ rmf[] rmf(path3 g, real[] t) return R; } -surface bispline(real[][] z, real[][] p, real[][] q, real[][] r, - real[] x, real[] y, bool[][] cond={}) +private real[][][] bispline0(real[][] z, real[][] p, real[][] q, real[][] r, + real[] x, real[] y, bool[][] cond={}) { // z[i][j] is the value at (x[i],y[j]) // p and q are the first derivatives with respect to x and y, respectively // r is the second derivative ddu/dxdy @@ -87,62 +88,49 @@ surface bispline(real[][] z, real[][] p, real[][] q, real[][] r, } } - surface s=surface(count); - s.index=new int[n][m]; - int k=-1; + real[][][] s=new real[count][][]; + int k=0; for(int i=0; i < n; ++i) { + int ip=i+1; bool[] condi=all ? null : cond[i]; real xi=x[i]; real[] zi=z[i]; - real[] zp=z[i+1]; + real[] zp=z[ip]; real[] ri=r[i]; - real[] rp=r[i+1]; + real[] rp=r[ip]; real[] pi=p[i]; - real[] pp=p[i+1]; + real[] pp=p[ip]; real[] qi=q[i]; - real[] qp=q[i+1]; - real xp=x[i+1]; + real[] qp=q[ip]; + real xp=x[ip]; real hx=(xp-xi)/3; - int[] indexi=s.index[i]; for(int j=0; j < m; ++j) { real yj=y[j]; - real yp=y[j+1]; + int jp=j+1; + real yp=y[jp]; if(all || condi[j]) { - triple[][] P=array(4,array(4,O)); real hy=(yp-yj)/3; real hxy=hx*hy; - // x and y directions - for(int k=0; k < 4; ++k) { - P[0][k] += xi*X; - P[k][0] += yj*Y; - P[1][k] += (xp+2*xi)/3*X; - P[k][1] += (yp+2*yj)/3*Y; - P[2][k] += (2*xp+xi)/3*X; - P[k][2] += (2*yp+yj)/3*Y; - P[3][k] += xp*X; - P[k][3] += yp*Y; - } - // z: value - P[0][0] += zi[j]*Z; - P[3][0] += zp[j]*Z; - P[0][3] += zi[j+1]*Z; - P[3][3] += zp[j+1]*Z; - // z: first derivative - P[1][0] += (P[0][0].z+hx*pi[j])*Z; - P[1][3] += (P[0][3].z+hx*pi[j+1])*Z; - P[2][0] += (P[3][0].z-hx*pp[j])*Z; - P[2][3] += (P[3][3].z-hx*pp[j+1])*Z; - P[0][1] += (P[0][0].z+hy*qi[j])*Z; - P[3][1] += (P[3][0].z+hy*qp[j])*Z; - P[0][2] += (P[0][3].z-hy*qi[j+1])*Z; - P[3][2] += (P[3][3].z-hy*qp[j+1])*Z; - // z: second derivative - P[1][1] += (P[0][1].z+P[1][0].z-P[0][0].z+hxy*ri[j])*Z; - P[1][2] += (P[0][2].z+P[1][3].z-P[0][3].z-hxy*ri[j+1])*Z; - P[2][1] += (P[2][0].z+P[3][1].z-P[3][0].z-hxy*rp[j])*Z; - P[2][2] += (P[2][3].z+P[3][2].z-P[3][3].z+hxy*rp[j+1])*Z; - s.s[++k]=patch(P); - indexi[j]=k; + real zij=zi[j]; + real zip=zi[jp]; + real zpj=zp[j]; + real zpp=zp[jp]; + real pij=hx*pi[j]; + real ppj=hx*pp[j]; + real qip=hy*qi[jp]; + real qpp=hy*qp[jp]; + real zippip=zip+hx*pi[jp]; + real zppmppp=zpp-hx*pp[jp]; + real zijqij=zij+hy*qi[j]; + real zpjqpj=zpj+hy*qp[j]; + + s[k]=new real[][] {{zij,zijqij,zip-qip,zip}, + {zij+pij,zijqij+pij+hxy*ri[j], + zippip-qip-hxy*ri[jp],zippip}, + {zpj-ppj,zpjqpj-ppj-hxy*rp[j], + zppmppp-qpp+hxy*rp[jp],zppmppp}, + {zpj,zpjqpj,zpp-qpp,zpp}}; + ++k; } } } @@ -150,11 +138,11 @@ surface bispline(real[][] z, real[][] p, real[][] q, real[][] r, return s; } -// return the surface described by a real matrix f, interpolated with +// return the surface values described by a real matrix f, interpolated with // xsplinetype and ysplinetype. -surface surface(real[][] f, real[] x, real[] y, - splinetype xsplinetype=null, splinetype ysplinetype=xsplinetype, - bool[][] cond={}) +real[][][] bispline(real[][] f, real[] x, real[] y, + splinetype xsplinetype=null, + splinetype ysplinetype=xsplinetype, bool[][] cond={}) { real epsilon=sqrtEpsilon*norm(y); if(xsplinetype == null) @@ -176,9 +164,7 @@ surface surface(real[][] f, real[] x, real[] y, real[][] p=transpose(tp); for(int i=0; i < n; ++i) r[i]=clamped(d1[i],d2[i])(y,p[i]); - surface s=bispline(f,p,q,r,x,y,cond); - if(xsplinetype == periodic) s.ucyclic(true); - if(ysplinetype == periodic) s.vcyclic(true); + real[][][] s=bispline0(f,p,q,r,x,y,cond); return s; } @@ -248,11 +234,11 @@ surface surface(triple f(pair z), real[] u, real[] v, vperiodic(fz) ? periodic : notaknot}; } else if(vsplinetype.length != 3) abort("vsplinetype must have length 3"); - surface sx=surface(fx,ipt,jpt,usplinetype[0],vsplinetype[0],active); - surface sy=surface(fy,ipt,jpt,usplinetype[1],vsplinetype[1],active); - surface sz=surface(fz,ipt,jpt,usplinetype[2],vsplinetype[2],active); + real[][][] sx=bispline(fx,ipt,jpt,usplinetype[0],vsplinetype[0],active); + real[][][] sy=bispline(fy,ipt,jpt,usplinetype[1],vsplinetype[1],active); + real[][][] sz=bispline(fz,ipt,jpt,usplinetype[2],vsplinetype[2],active); - surface s=surface(sx.s.length); + surface s=surface(sx.length); s.index=new int[nu][nv]; int k=-1; for(int i=0; i < nu; ++i) { @@ -261,12 +247,20 @@ surface surface(triple f(pair z), real[] u, real[] v, indexi[j]=++k; } - for(int k=0; k < sx.s.length; ++k) { + for(int k=0; k < sx.length; ++k) { triple[][] Q=new triple[4][]; - for(int i=0; i < 4 ; ++i) - Q[i]=sequence(new triple(int j) { - return (sx.s[k].P[i][j].z,sy.s[k].P[i][j].z,sz.s[k].P[i][j].z); - },4); + real[][] Px=sx[k]; + real[][] Py=sy[k]; + real[][] Pz=sz[k]; + for(int i=0; i < 4 ; ++i) { + real[] Pxi=Px[i]; + real[] Pyi=Py[i]; + real[] Pzi=Pz[i]; + Q[i]=new triple[] {(Pxi[0],Pyi[0],Pzi[0]), + (Pxi[1],Pyi[1],Pzi[1]), + (Pxi[2],Pyi[2],Pzi[2]), + (Pxi[3],Pyi[3],Pzi[3])}; + } s.s[k]=patch(Q); } @@ -282,8 +276,8 @@ surface surface(triple f(pair z), real[] u, real[] v, path3 interp(path3 a, path3 b, real t) { int n=size(a); - return path3(sequence(new triple(int i) {return interp(precontrol(a,i), - precontrol(b,i),t);},n), + return path3(sequence(new triple(int i) { + return interp(precontrol(a,i),precontrol(b,i),t);},n), sequence(new triple(int i) {return interp(point(a,i),point(b,i),t);},n), sequence(new triple(int i) {return interp(postcontrol(a,i), postcontrol(b,i),t);},n), @@ -294,12 +288,15 @@ path3 interp(path3 a, path3 b, real t) struct tube { surface s; - path3 center; + path3 center; // tube axis - void operator init(path3 p, real width, int sectors=4, - real granularity=linegranularity) { - sectors += sectors % 2; // Must be even. - int h=quotient(sectors,2); + void Null(transform3) {} + void Null(transform3, bool) {} + + void operator init(path3 p, real width, render render=defaultrender, + void cylinder(transform3)=Null, + void sphere(transform3, bool half)=Null, + void tube(path3, path3)=null) { real r=0.5*width; void generate(path3 p) { @@ -308,31 +305,41 @@ struct tube for(int i=0; i < n; ++i) { triple v=point(p,i); triple u=point(p,i+1)-v; - s.append(shift(v)*align(unit(u))*scale(r,r,abs(u))*unitcylinder); + transform3 t=shift(v)*align(unit(u))*scale(r,r,abs(u)); + s.append(t*unitcylinder); + cylinder(t); } center=center&p; } else { real[] T; path3 G; for(int i=0; i < n; ++i) - render(subpath(p,i,i+1),granularity, + render(subpath(p,i,i+1), new void(path3 g, real s) { G=G&g; T.push(i+s); - }); + },render); T.push(n); T.cyclic=cyclic(p); rmf[] rmf=rmf(p,T); triple f(pair t) { rmf R=rmf[round(t.x)]; - return point(G,t.x)+r*(R.r*cos(t.y)-R.s*sin(t.y)); + int n=round(t.y); + static real[] x={1,0,-1,0}; + static real[] y={0,1,0,-1}; + return point(G,t.x)+r*(R.r*x[n]-R.s*y[n]); } - real[] v=uniform(0,2pi,sectors); + static real[] v={0,1,2,3,0}; + static real[] circular(real[] x, real[] y) { + static real a=8/3*(sqrt(2)-1); + return a*periodic(x,y); + } + static splinetype[] Monotonic={monotonic,monotonic,monotonic}; - static splinetype[] Periodic={periodic,periodic,periodic}; + static splinetype[] Circular={circular,circular,circular}; if(T.length > 0) { - surface S=surface(f,sequence(T.length),v,Monotonic,Periodic); + surface S=surface(f,sequence(T.length),v,Monotonic,Circular); s.append(S); // Compute center of tube: @@ -341,19 +348,52 @@ struct tube triple[] pre=new triple[n+1]; triple[] point=new triple[n+1]; triple[] post=new triple[n+1]; + int[] index=S.index[0]; - pre[0]=point[0]=0.5*(S.s[index[0]].P[0][0]+S.s[index[h]].P[0][0]); + triple Point; + for(int m=0; m < 4; ++m) + Point += S.s[index[m]].P[0][0]; + pre[0]=point[0]=0.25*Point; + for(int i=0; i < n; ++i) { index=S.index[i]; - triple [][] P=S.s[index[0]].P; - triple [][] Q=S.s[index[h]].P; - post[i]=0.5*(P[1][0]+Q[1][0]); - pre[i+1]=0.5*(P[2][0]+Q[2][0]); - point[i+1]=0.5*(P[3][0]+Q[3][0]); + triple Pre,Point,Post; + for(int m=0; m < 4; ++m) { + triple [][] P=S.s[index[m]].P; + Post += P[1][0]; + Pre += P[2][0]; + Point += P[3][0]; + } + post[i]=0.25*Post; + pre[i+1]=0.25*Pre; + point[i+1]=0.25*Point; + } + index=S.index[n-1]; - post[n]=0.5*(S.s[index[0]].P[3][0]+S.s[index[h]].P[3][0]); - center=center&path3(pre,point,post,array(n+1,false),T.cyclic); + triple Post; + for(int m=0; m < 4; ++m) + Post += S.s[index[m]].P[3][0]; + post[n]=0.25*Post; + + bool[] b=array(n+1,false); + path3 Center=path3(pre,point,post,b,T.cyclic); + center=center&Center; + + if(tube != null) { // Compute path along tube + triple[] pre=new triple[n+1]; + triple[] point=new triple[n+1]; + triple[] post=new triple[n+1]; + pre[0]=point[0]=S.s[S.index[0][0]].P[0][0]; + for(int i=0; i < n; ++i) { + triple [][] P=S.s[S.index[i][0]].P; + post[i]=P[1][0]; + pre[i+1]=P[2][0]; + point[i+1]=P[3][0]; + } + post[n]=S.s[S.index[n-1][0]].P[3][0]; + tube(Center,path3(pre,point,post,b,T.cyclic)); + } } } } @@ -363,11 +403,16 @@ struct tube int begin=0; int n=length(p); for(int i=cyclic ? 0 : 1; i < n; ++i) - if(abs(dir(p,i,1)-dir(p,i,-1)) > sqrtEpsilon) { - generate(subpath(p,begin,i)); - s.append(shift(point(p,i))*t*align(dir(p,i,-1))*unithemisphere); - begin=i; - } + if(abs(dir(p,i,1)-dir(p,i,-1)) > sqrtEpsilon) { + generate(subpath(p,begin,i)); + triple dir=dir(p,i,-1); + s.append(shift(point(p,i))*t*align(dir)* + (dir != O ? unithemisphere : unitsphere)); + int L=length(center); + sphere(shift(point(center,L))*t*align(dir(center,L,-1)), + half=straight(p,i-1) && straight(p,i)); + begin=i; + } generate(subpath(p,begin,n)); } } |