diff options
author | Karl Berry <karl@freefriends.org> | 2016-02-07 00:27:20 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-02-07 00:27:20 +0000 |
commit | 0f5e19a268f4d86c2897f590563f21c8277c18d1 (patch) | |
tree | 7e65891f29ccde62ed60cbcc94e7fb7631429ac2 /Build/source/utils/asymptote/base/three_surface.asy | |
parent | 1b8f7f1bf982c75d77d85ac6855d48332cd41ca4 (diff) |
asy 2.36 sources
git-svn-id: svn://tug.org/texlive/trunk@39610 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Build/source/utils/asymptote/base/three_surface.asy')
-rw-r--r-- | Build/source/utils/asymptote/base/three_surface.asy | 290 |
1 files changed, 206 insertions, 84 deletions
diff --git a/Build/source/utils/asymptote/base/three_surface.asy b/Build/source/utils/asymptote/base/three_surface.asy index f2f21eb826c..175ef562d80 100644 --- a/Build/source/utils/asymptote/base/three_surface.asy +++ b/Build/source/utils/asymptote/base/three_surface.asy @@ -9,12 +9,21 @@ string meshname(string name) {return name+" mesh";} private real Fuzz=10.0*realEpsilon; private real nineth=1/9; +// Return the default Coons interior control point for a Bezier triangle +// based on the cyclic path3 external. +triple coons3(path3 external) { + return 0.25*(precontrol(external,0)+postcontrol(external,0)+ + precontrol(external,1)+postcontrol(external,1)+ + precontrol(external,2)+postcontrol(external,2))- + (point(external,0)+point(external,1)+point(external,2))/6; +} + struct patch { triple[][] P; - triple[] normals; // Optionally specify 4 normal vectors at the corners. pen[] colors; // Optionally specify 4 corner colors. bool straight; // Patch is based on a piecewise straight external path. bool3 planar; // Patch is planar. + bool triangular; // Patch is a Bezier triangle. path3 external() { return straight ? P[0][0]--P[3][0]--P[3][3]--P[0][3]--cycle : @@ -24,20 +33,40 @@ struct patch { P[0][3]..controls P[0][2] and P[0][1]..cycle; } + path3 externaltriangular() { + return + P[0][0]..controls P[1][0] and P[2][0].. + P[3][0]..controls P[3][1] and P[3][2].. + P[3][3]..controls P[2][2] and P[1][1]..cycle; + } + triple[] internal() { return new triple[] {P[1][1],P[2][1],P[2][2],P[1][2]}; } + triple[] internaltriangular() { + return new triple[] {P[2][1]}; + } + triple cornermean() { return 0.25*(P[0][0]+P[0][3]+P[3][0]+P[3][3]); } + triple cornermeantriangular() { + return (P[0][0]+P[3][0]+P[3][3])/3; + } + triple[] corners() {return new triple[] {P[0][0],P[3][0],P[3][3],P[0][3]};} + triple[] cornerstriangular() {return new triple[] {P[0][0],P[3][0],P[3][3]};} real[] map(real f(triple)) { return new real[] {f(P[0][0]),f(P[3][0]),f(P[3][3]),f(P[0][3])}; } + real[] maptriangular(real f(triple)) { + return new real[] {f(P[0][0]),f(P[3][0]),f(P[3][3])}; + } + triple Bu(int j, real u) {return bezier(P[0][j],P[1][j],P[2][j],P[3][j],u);} triple BuP(int j, real u) {return bezierP(P[0][j],P[1][j],P[2][j],P[3][j],u);} triple BuPP(int j, real u) { @@ -70,6 +99,13 @@ struct patch { return bezier(Bu(0,u),Bu(1,u),Bu(2,u),Bu(3,u),v); } + triple pointtriangular(real u, real v) { + real w=1-u-v; + return w^2*(w*P[0][0]+3*(u*P[1][0]+v*P[1][1]))+ + u^2*(u*P[3][0]+3*(w*P[2][0]+v*P[3][1]))+ + 6*u*v*w*P[2][1]+v^2*(v*P[3][3]+3*(w*P[2][2]+u*P[3][2])); + } + // compute normal vectors for degenerate cases private triple normal0(real u, real v, real epsilon) { triple n=0.5*(cross(bezier(BuPP(0,u),BuPP(1,u),BuPP(2,u),BuPP(3,u),v), @@ -131,13 +167,50 @@ struct patch { return abs(n) > epsilon ? n : normal0(0,1,epsilon); } + triple normal00triangular() { + triple n=9*cross(P[1][0]-P[0][0],P[1][1]-P[0][0]); + real epsilon=fuzz*change2(P); + return abs(n) > epsilon ? n : normal0(0,0,epsilon); + } + + triple normal10triangular() { + triple n=9*cross(P[3][0]-P[2][0],P[3][1]-P[2][0]); + real epsilon=fuzz*change2(P); + return abs(n) > epsilon ? n : normal0(1,0,epsilon); + } + + triple normal01triangular() { + triple n=9*cross(P[3][2]-P[2][2],P[3][3]-P[2][2]); + real epsilon=fuzz*change2(P); + return abs(n) > epsilon ? n : normal0(0,1,epsilon); + } + + // Compute one-third of the directional derivative of a Bezier triangle in the u + // direction at point (u,v). + private triple bu(real u, real v) { + real w=1-u-v; + return u*(w*2-u)*P[2][0]+2*v*(w-u)*P[2][1]+w*(w-2*u)*P[1][0]+ + u*(u*P[3][0]+2*v*P[3][1])+v*v*P[3][2]-w*(2*v*P[1][1]+w*P[0][0])- + v*v*P[2][2]; + } + + // Compute one-third of the directional derivative of a Bezier triangle in the v + // direction at point (u,v). + private triple bv(real u, real v) { + real w=1-u-v; + return u*2*(w-v)*P[2][1]+v*(2*w-v)*P[2][2]+w*(w-2*v)*P[1][1]+ + u*(u*P[3][1]+2*v*P[3][2])+v*v*P[3][3]-w*(2*u*P[1][0]+w*P[0][0])- + u*u*P[2][0]; + } + + // Compute the normal of a Bezier triangle at (u,v) + triple normaltriangular(real u, real v) { + // TODO: handle degeneracy + return 9*cross(bu(u,v),bv(u,v)); + } + pen[] colors(material m, light light=currentlight) { bool nocolors=colors.length == 0; - if(normals.length > 0) - return new pen[] {color(normals[0],nocolors ? m : colors[0],light), - color(normals[1],nocolors ? m : colors[1],light), - color(normals[2],nocolors ? m : colors[2],light), - color(normals[3],nocolors ? m : colors[3],light)}; if(planar) { triple normal=normal(0.5,0.5); return new pen[] {color(normal,nocolors ? m : colors[0],light), @@ -151,12 +224,38 @@ struct patch { color(normal01(),nocolors ? m : colors[3],light)}; } + pen[] colorstriangular(material m, light light=currentlight) { + bool nocolors=colors.length == 0; + if(planar) { + triple normal=normal(1/3,1/3); + return new pen[] {color(normal,nocolors ? m : colors[0],light), + color(normal,nocolors ? m : colors[1],light), + color(normal,nocolors ? m : colors[2],light)}; + } + return new pen[] {color(normal00(),nocolors ? m : colors[0],light), + color(normal10(),nocolors ? m : colors[1],light), + color(normal01(),nocolors ? m : colors[2],light)}; + } + triple min3,max3; bool havemin3,havemax3; void init() { havemin3=false; havemax3=false; + if(triangular) { + external=externaltriangular; + internal=internaltriangular; + cornermean=cornermeantriangular; + corners=cornerstriangular; + map=maptriangular; + point=pointtriangular; + normal=normaltriangular; + normal00=normal00triangular; + normal10=normal10triangular; + normal01=normal01triangular; + colors=colorstriangular; + } } triple min(triple bound=P[0][0]) { @@ -191,63 +290,81 @@ struct patch { return minratio(Q,d*bound)/d; // d is negative } - void operator init(triple[][] P, triple[] normals=new triple[], + void operator init(triple[][] P, pen[] colors=new pen[], bool straight=false, - bool3 planar=default, bool copy=true) { - init(); + bool3 planar=default, bool triangular=false, + bool copy=true) { this.P=copy ? copy(P) : P; - if(normals.length != 0) - this.normals=copy(normals); if(colors.length != 0) this.colors=copy(colors); - this.planar=planar; this.straight=straight; + this.planar=planar; + this.triangular=triangular; + init(); } void operator init(pair[][] P, triple plane(pair)=XYplane, - bool straight=false) { + bool straight=false, bool triangular=false) { triple[][] Q=new triple[4][]; for(int i=0; i < 4; ++i) { pair[] Pi=P[i]; Q[i]=sequence(new triple(int j) {return plane(Pi[j]);},4); } - operator init(Q,straight); - planar=true; + operator init(Q,straight,planar=true,triangular); } void operator init(patch s) { - operator init(s.P,s.normals,s.colors,s.straight); - } + operator init(s.P,s.colors,s.straight,s.planar,s.triangular); + } - // A constructor for a convex cyclic path3 of length <= 4 with optional - // arrays of 4 internal points, corner normals, and pens. - void operator init(path3 external, triple[] internal=new triple[], - triple[] normals=new triple[], pen[] colors=new pen[], + // A constructor for a cyclic path3 of length 3 with a specified + // internal point, corner normals, and pens (rendered as a Bezier triangle). + void operator init(path3 external, triple internal, pen[] colors=new pen[], bool3 planar=default) { + triangular=true; + this.planar=planar; init(); + if(colors.length != 0) + this.colors=copy(colors); + + P=new triple[][] { + {point(external,0)}, + {postcontrol(external,0),precontrol(external,0)}, + {precontrol(external,1),internal,postcontrol(external,2)}, + {point(external,1),postcontrol(external,1),precontrol(external,2), + point(external,2)} + }; + } + // A constructor for a convex cyclic path3 of length <= 4 with optional + // arrays of internal points (4 for a Bezier patch, 1 for a Bezier + // triangle), and pens. + void operator init(path3 external, triple[] internal=new triple[], + pen[] colors=new pen[], bool3 planar=default) { if(internal.length == 0 && planar == default) this.planar=normal(external) != O; else this.planar=planar; int L=length(external); + + if(L == 3) { + operator init(external,internal.length == 1 ? internal[0] : + coons3(external),colors,this.planar); + straight=piecewisestraight(external); + return; + } + if(L > 4 || !cyclic(external)) abort("cyclic path3 of length <= 4 expected"); if(L == 1) { external=external--cycle--cycle--cycle; if(colors.length > 0) colors.append(array(3,colors[0])); - if(normals.length > 0) normals.append(array(3,normals[0])); } else if(L == 2) { external=external--cycle--cycle; if(colors.length > 0) colors.append(array(2,colors[0])); - if(normals.length > 0) normals.append(array(2,normals[0])); - } else if(L == 3) { - external=external--cycle; - if(colors.length > 0) colors.push(colors[0]); - if(normals.length > 0) normals.push(normals[0]); } - if(normals.length != 0) - this.normals=copy(normals); + + init(); if(colors.length != 0) this.colors=copy(colors); @@ -261,7 +378,7 @@ struct patch { +3*(precontrol(external,j-1)+ postcontrol(external,j+1)) -point(external,j+2)); - } else straight=false; + } P=new triple[][] { {point(external,0),precontrol(external,0),postcontrol(external,3), @@ -275,16 +392,13 @@ struct patch { // A constructor for a convex quadrilateral. void operator init(triple[] external, triple[] internal=new triple[], - triple[] normals=new triple[], pen[] colors=new pen[], - bool3 planar=default) { + pen[] colors=new pen[], bool3 planar=default) { init(); if(internal.length == 0 && planar == default) this.planar=normal(external) != O; else this.planar=planar; - if(normals.length != 0) - this.normals=copy(normals); if(colors.length != 0) this.colors=copy(colors); @@ -313,41 +427,46 @@ struct patch { patch operator * (transform3 t, patch s) { patch S; - S.P=new triple[4][4]; - for(int i=0; i < 4; ++i) { + S.P=new triple[s.P.length][]; + for(int i=0; i < s.P.length; ++i) { triple[] si=s.P[i]; triple[] Si=S.P[i]; - for(int j=0; j < 4; ++j) + for(int j=0; j < si.length; ++j) Si[j]=t*si[j]; } - if(s.normals.length > 0) { - transform3 t0=shiftless(t); - t0=determinant(t0) == 0 ? identity4 : transpose(inverse(t0)); - for(int i=0; i < s.normals.length; ++i) - S.normals[i]=t0*s.normals[i]; - } - S.colors=copy(s.colors); S.planar=s.planar; S.straight=s.straight; + S.triangular=s.triangular; + S.init(); return S; } patch reverse(patch s) { + assert(!s.triangular); patch S; S.P=transpose(s.P); - if(s.normals.length > 0) - S.normals= - new triple[] {s.normals[0],s.normals[3],s.normals[2],s.normals[1]}; if(s.colors.length > 0) S.colors=new pen[] {s.colors[0],s.colors[3],s.colors[2],s.colors[1]}; - S.planar=s.planar; S.straight=s.straight; + S.planar=s.planar; return S; } +// Return a degenerate tensor patch representation of a Bezier triangle. +patch tensor(patch s) { + if(!s.triangular) return patch(s); + triple[][] P=s.P; + return patch(new triple[][] {{P[0][0],P[0][0],P[0][0],P[0][0]}, + {P[1][0],P[1][0]*2/3+P[1][1]/3,P[1][0]/3+P[1][1]*2/3,P[1][1]}, + {P[2][0],P[2][0]/3+P[2][1]*2/3,P[2][1]*2/3+P[2][2]/3,P[2][2]}, + {P[3][0],P[3][1],P[3][2],P[3][3]}}, + s.colors.length > 0 ? new pen[] {s.colors[0],s.colors[1],s.colors[2],s.colors[0]} : new pen[], + s.straight,s.planar,false,false); +} + // Return the tensor product patch control points corresponding to path p // and points internal. pair[][] tensor(path p, pair[] internal) @@ -589,7 +708,7 @@ path[] regularize(path p, bool checkboundary=true) struct surface { patch[] s; - int index[][]; + int index[][];// Position of patch corresponding to major U,V parameter in s. bool vcyclic; bool empty() { @@ -612,11 +731,11 @@ struct surface { this.vcyclic=s.vcyclic; } - void operator init(triple[][][] P, triple[][] normals=new triple[][], - pen[][] colors=new pen[][], bool3 planar=default) { + void operator init(triple[][][] P, pen[][] colors=new pen[][], + bool3 planar=default, bool triangular=false) { s=sequence(new patch(int i) { - return patch(P[i],normals.length == 0 ? new triple[] : normals[i], - colors.length == 0 ? new pen[] : colors[i],planar); + return patch(P[i],colors.length == 0 ? new pen[] : colors[i],planar, + triangular); },P.length); } @@ -701,8 +820,13 @@ struct surface { // A constructor for a possibly nonconvex simple cyclic path in a given plane. void operator init(path p, triple plane(pair)=XYplane) { bool straight=piecewisestraight(p); - for(path g : regularize(p)) - s.push(patch(coons(g),plane,straight)); + for(path g : regularize(p)) { + if(length(g) == 3) { + path3 G=path3(g,plane); + s.push(patch(G,coons3(G))); + } else + s.push(patch(coons(g),plane,straight)); + } } void operator init(explicit path[] g, triple plane(pair)=XYplane) { @@ -712,19 +836,17 @@ struct surface { // A general surface constructor for both planar and nonplanar 3D paths. void construct(path3 external, triple[] internal=new triple[], - triple[] normals=new triple[], pen[] colors=new pen[], - bool3 planar=default) { + pen[] colors=new pen[], bool3 planar=default) { int L=length(external); if(!cyclic(external)) abort("cyclic path expected"); if(L <= 3 && piecewisestraight(external)) { - s.push(patch(external,internal,normals,colors,planar=true)); + s.push(patch(external,internal,colors,planar)); return; } // Construct a surface from a possibly nonconvex planar cyclic path3. - if(planar != false && internal.length == 0 && normals.length == 0 && - colors.length == 0) { + if(planar != false && internal.length == 0 && colors.length == 0) { triple n=normal(external); if(n != O) { transform3 T=align(n); @@ -737,7 +859,7 @@ struct surface { } if(L <= 4 || internal.length > 0) { - s.push(patch(external,internal,normals,colors,planar)); + s.push(patch(external,internal,colors,planar)); return; } @@ -746,40 +868,33 @@ struct surface { pen[] p; triple[] n; bool nocolors=colors.length == 0; - bool nonormals=normals.length == 0; triple center; for(int i=0; i < L; ++i) center += point(external,i); center *= factor; if(!nocolors) p=new pen[] {mean(colors)}; - if(!nonormals) - n=new triple[] {factor*sum(normals)}; // Use triangles for nonplanar surfaces. int step=normal(external) == O ? 1 : 2; int i=0; int end; while((end=i+step) < L) { s.push(patch(subpath(external,i,end)--center--cycle, - nonormals ? n : concat(normals[i:end+1],n), nocolors ? p : concat(colors[i:end+1],p),planar)); i=end; } s.push(patch(subpath(external,i,L)--center--cycle, - nonormals ? n : concat(normals[i:],normals[0:1],n), nocolors ? p : concat(colors[i:],colors[0:1],p),planar)); } void operator init(path3 external, triple[] internal=new triple[], - triple[] normals=new triple[], pen[] colors=new pen[], - bool3 planar=default) { + pen[] colors=new pen[], bool3 planar=default) { s=new patch[]; - construct(external,internal,normals,colors,planar); + construct(external,internal,colors,planar); } void operator init(explicit path3[] external, triple[][] internal=new triple[][], - triple[][] normals=new triple[][], pen[][] colors=new pen[][], bool3 planar=default) { s=new patch[]; if(planar == true) {// Assume all path3 elements share a common normal. @@ -801,14 +916,12 @@ struct surface { for(int i=0; i < external.length; ++i) construct(external[i], internal.length == 0 ? new triple[] : internal[i], - normals.length == 0 ? new triple[] : normals[i], colors.length == 0 ? new pen[] : colors[i],planar); } void push(path3 external, triple[] internal=new triple[], - triple[] normals=new triple[] ,pen[] colors=new pen[], - bool3 planar=default) { - s.push(patch(external,internal,normals,colors,planar)); + pen[] colors=new pen[], bool3 planar=default) { + s.push(patch(external,internal,colors,planar)); } // Construct the surface of rotation generated by rotating g @@ -1111,7 +1224,7 @@ triple[][] subpatch(triple[][] P, pair a, pair b) patch subpatch(patch s, pair a, pair b) { assert(a.x >= 0 && a.y >= 0 && b.x <= 1 && b.y <= 1 && - a.x < b.x && a.y < b.y); + a.x < b.x && a.y < b.y && !s.triangular); return patch(subpatch(s.P,a,b),s.straight,s.planar); } @@ -1244,8 +1357,14 @@ void draw3D(frame f, int type=0, patch s, triple center=O, material m, if(prc()) PRCshininess=PRCshininess(m.shininess); - draw(f,s.P,center,s.straight,m.p,m.opacity,m.shininess,PRCshininess, - s.planar ? s.normal(0.5,0.5) : O,s.colors,interaction.type,prc); + if(s.triangular) + drawbeziertriangle(f,s.P,center,s.straight && s.planar,m.p, + m.opacity,m.shininess,PRCshininess,s.colors, + interaction.type); + else + draw(f,s.P,center,s.straight && s.planar,m.p,m.opacity,m.shininess, + PRCshininess,s.planar ? s.normal(0.5,0.5) : O,s.colors, + interaction.type,prc); } // Draw triangles on a frame. @@ -1337,11 +1456,13 @@ void draw(picture pic=currentpicture, triple[] v, int[][] vi, pic.addPoint(v[viij]); } -void drawPRCsphere(frame f, transform3 t=identity4, bool half=false, material m, - light light=currentlight, render render=defaultrender) +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); + drawPRCsphere(f,t,half,m.p,m.opacity,PRCshininess(m.shininess), + render.sphere); } void drawPRCcylinder(frame f, transform3 t=identity4, material m, @@ -1368,9 +1489,10 @@ void drawPRCtube(frame f, path3 center, path3 g, material m, void tensorshade(transform t=identity(), frame f, patch s, material m, light light=currentlight, projection P) { + + if(s.triangular) s=tensor(s); tensorshade(f,box(t*s.min(P),t*s.max(P)),m.diffuse(), - s.colors(m,light),t*project(s.external(),P,1), - t*project(s.internal(),P)); + s.colors(m,light),t*project(s.external(),P,1),t*project(s.internal(),P)); } restricted pen[] nullpens={nullpen}; @@ -1397,7 +1519,7 @@ void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, real[][] depth=new real[s.s.length][]; for(int i=0; i < depth.length; ++i) - depth[i]=new real[] {abs(camera-s.s[i].cornermean()),i}; + depth[i]=new real[] {dot(P.normal,camera-s.s[i].cornermean()),i}; depth=sort(depth); @@ -1444,7 +1566,7 @@ void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1, real[][] depth=new real[s.s.length][]; for(int i=0; i < depth.length; ++i) - depth[i]=new real[] {abs(camera-s.s[i].cornermean()),i}; + depth[i]=new real[] {dot(P.normal,camera-s.s[i].cornermean()),i}; depth=sort(depth); |