From 9e32dd6aee7faf4e59888cfbd7a927d497b563ad Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 8 Jun 2009 00:57:31 +0000 Subject: asymptote 1.76 git-svn-id: svn://tug.org/texlive/trunk@13664 c570f23f-e606-0410-a88d-b1316a301751 --- Build/source/utils/asymptote/base/bezulate.asy | 37 +++---- Build/source/utils/asymptote/base/fontsize.asy | 2 +- Build/source/utils/asymptote/base/labelpath3.asy | 27 +++--- Build/source/utils/asymptote/base/plain_Label.asy | 20 +++- Build/source/utils/asymptote/base/plain_paths.asy | 10 +- Build/source/utils/asymptote/base/plain_pens.asy | 6 +- .../source/utils/asymptote/base/plain_strings.asy | 19 ++++ Build/source/utils/asymptote/base/three.asy | 106 ++++++++++++++------- Build/source/utils/asymptote/base/three_light.asy | 47 +++++---- .../source/utils/asymptote/base/three_surface.asy | 16 ++++ 10 files changed, 190 insertions(+), 100 deletions(-) (limited to 'Build/source/utils/asymptote/base') diff --git a/Build/source/utils/asymptote/base/bezulate.asy b/Build/source/utils/asymptote/base/bezulate.asy index 01b3024f7b6..2b852623faf 100644 --- a/Build/source/utils/asymptote/base/bezulate.asy +++ b/Build/source/utils/asymptote/base/bezulate.asy @@ -1,13 +1,19 @@ // Bezier triangulation routines written by Orest Shardt, 2008. -private real fuzz=1e-6; +private real fuzz=sqrtEpsilon; real duplicateFuzz=1e-3; // Work around font errors. +private real[][] intersections(pair a, pair b, path p) +{ + pair delta=fuzz*unit(b-a); + return intersections(a-delta--b+delta,p,fuzz); +} + int countIntersections(path[] p, pair start, pair end) { int intersects=0; for(path q : p) - intersects += intersections(q,start--end,fuzz).length; + intersects += intersections(start,end,q).length; return intersects; } @@ -101,27 +107,23 @@ void connect(path[] paths, path[] result, path[] patch) pair start=point(inners[curveIndex],0); // find first intersection of line segment with outer curve - path line = start--start+d*direction; - real[][] ints=intersections(line,outer,fuzz); + real[][] ints=intersections(start,start+d*direction,outer); assert(ints.length != 0); real endtime=ints[0][1]; // endtime is time on outer pair end = point(outer,endtime); - line = start--end; - path rline = reverse(line); - // find first intersection of rline segment with any inner curve + // find first intersection of end--start with any inner curve real starttime=0; // starttime is time on inners[curveIndex] real earliestTime=1; for(int j=0; j < inners.length; ++j) { - real[][] ints=intersections(rline,inners[j],fuzz); + real[][] ints=intersections(end,start,inners[j]); if(ints.length > 0 && ints[0][0] < earliestTime) { - earliestTime=ints[0][0]; // time on rline + earliestTime=ints[0][0]; // time on end--start starttime=ints[0][1]; // time on inner curve curveIndex=j; } } start=point(inners[curveIndex],starttime); - line = start--end; real timeoffset=2; bool found=false; @@ -146,7 +148,7 @@ void connect(path[] paths, path[] result, path[] patch) } } - if(!found)timeoffset=-2; + if(!found) timeoffset=-2; while(!found && timeoffset < -fuzz) { timeoffset /= 2; if(countIntersections(allCurves,start, @@ -179,20 +181,11 @@ void connect(path[] paths, path[] result, path[] patch) } } -int countIntersections(path g, pair p, pair q) -{ - int ints=0; - int l=length(g); - for(int i=1; i <= l; ++i) - ints += intersections(subpath(g,i-1,i),p--q,fuzz).length; - return ints; -} - bool checkSegment(path g, pair p, pair q) { pair mid=0.5*(p+q); - return countIntersections(g,p,q) == 4 && inside(g,mid,zerowinding) && - intersections(g,mid).length == 0; + return intersections(p,q,g).length == 2 && + inside(g,mid,zerowinding) && intersections(g,mid).length == 0; } path subdivide(path p) diff --git a/Build/source/utils/asymptote/base/fontsize.asy b/Build/source/utils/asymptote/base/fontsize.asy index 0c0c6a0dcca..4575f3480fa 100644 --- a/Build/source/utils/asymptote/base/fontsize.asy +++ b/Build/source/utils/asymptote/base/fontsize.asy @@ -1 +1 @@ -usepackage("fix-cm"); +if(latex()) usepackage("fix-cm"); diff --git a/Build/source/utils/asymptote/base/labelpath3.asy b/Build/source/utils/asymptote/base/labelpath3.asy index acfa64d528f..b8a946a07ae 100644 --- a/Build/source/utils/asymptote/base/labelpath3.asy +++ b/Build/source/utils/asymptote/base/labelpath3.asy @@ -2,11 +2,7 @@ // Author: Jens Schwaiger import three; -size(7.5cm,0); -real eps=100*realEpsilon; -currentprojection=perspective(20,18,8); -currentlight=light(8,10,2); -//texpreamble("\textwidth=50cm"); // Avoid line breaking in long texts +private real eps=100*realEpsilon; triple nextnormal(triple p, triple q) { @@ -34,13 +30,14 @@ triple[] nextframe(path3 p, real reltimestart, triple[] start, real real lg=reltimeend-reltimestart; if(lg <= 0) return start; bf[0]=start; - for(int i=1; i < subdiv+1; i=i+1) { + int n=subdiv+1; + for(int i=1; i < n; ++i) bf[i][0]=dir(p,reltime(p,reltimestart+(i/subdiv)*lg)); - }; - for(int i=1; i < subdiv+1; i=i+1) { + + for(int i=1; i < n; ++i) { bf[i][1]=nextnormal(bf[i-1][1],bf[i][0]); bf[i][2]=cross(bf[i][0],bf[i][1]); - }; + } return bf[subdiv]; } @@ -48,8 +45,7 @@ surface labelpath(string txt, path3 p, real angle=90, triple optional=O) { real Cos=Cos(angle); real Sin=Sin(angle); - path[] text=shift(-labelmargin(currentpen)*NE)* - texpath(Label(txt,(0,0),NE,basealign)); + path[] text=texpath(Label(txt,(0,0),Align,basealign)); text=scale(1/(max(text).x-min(text).x))*text; path[][] decompose=containmentTree(text); @@ -59,7 +55,7 @@ surface labelpath(string txt, path3 p, real angle=90, triple optional=O) xpos[i][1]=i; real pos0=0.5(max(decompose[i]).x+min(decompose[i]).x); xpos[i][0]=pos0; - }; + } xpos=sort(xpos); // sort by distance from 0; triple[] pos=new triple[decompose.length]; real lg=arclength(p); @@ -70,17 +66,18 @@ surface labelpath(string txt, path3 p, real angle=90, triple optional=O) triple[][] bfr=new triple[decompose.length][3]; for(int j=0; j < decompose.length; ++j) { bfr[j]=nextframe(p,tm0,t0,xpos[j][0]); - tm0=xpos[j][0]; t0=bfr[j];}; + tm0=xpos[j][0]; t0=bfr[j]; + } transform3[] mt=new transform3[bfr.length]; for(int j=0; j < bfr.length; ++j) { triple f2=Cos*bfr[j][1]+Sin*bfr[j][2]; triple f3=Sin*bfr[j][1]+Cos*bfr[j][2]; mt[j]=shift(relpoint(p,xpos[j][0]))*transform3(bfr[j][0],f2,f3); - }; + } for(int j=0; j < bfr.length; ++j) { path[] dc=decompose[(int) xpos[j][1]]; pair pos0=(0.5(max(dc).x+min(dc).x),0); sf.append(mt[j]*surface(scale(lg)*shift(-pos0)*dc)); - }; + } return sf; } diff --git a/Build/source/utils/asymptote/base/plain_Label.asy b/Build/source/utils/asymptote/base/plain_Label.asy index 1279880ca3a..3c11a2cedbd 100644 --- a/Build/source/utils/asymptote/base/plain_Label.asy +++ b/Build/source/utils/asymptote/base/plain_Label.asy @@ -571,7 +571,12 @@ path[] texpath(Label L, bool tex=settings.tex != "none") path[] g; string s=L.s; - pen p=L.p; + pen p=fontcommand(font(L.p))+fontsize(fontsize(L.p)); + + // PDF tex engines lose track of the baseline. + bool adjust=tex && basealign(L.p) == 1 && pdf(); + if(adjust) p=p+basealign; + int k=0; int i; while((i=find(stringcache == s,++k)) >= 0) { @@ -582,7 +587,16 @@ path[] texpath(Label L, bool tex=settings.tex != "none") } if(i == -1) { - g=tex ? _texpath(s,p) : textpath(s,p); + if(tex) { + if(adjust) { + g=_texpath("."+s,p); + if(g.length == 0) return g; + real y=min(g[0]).y; + g.delete(0); + g=shift(0,-y)*g; + } else g=_texpath(s,p); + } else g=textpath(s,p); + stringcache.push(s); pencache.push(p); pathcache.push(g); @@ -593,7 +607,7 @@ path[] texpath(Label L, bool tex=settings.tex != "none") pair m=min(g); pair M=max(g); pair dir=rectify(inverse(L.T)*-L.align.dir); - if(basealign(p) == 1) + if(tex && basealign(L.p) == 1) dir -= (0,(1-dir.y)*m.y/(M.y-m.y)); a=m+realmult(dir,M-m); diff --git a/Build/source/utils/asymptote/base/plain_paths.asy b/Build/source/utils/asymptote/base/plain_paths.asy index 486f3f0cc7b..d457fa5bc28 100644 --- a/Build/source/utils/asymptote/base/plain_paths.asy +++ b/Build/source/utils/asymptote/base/plain_paths.asy @@ -329,19 +329,21 @@ pair inside(path p, pen fillrule=currentpen) int n=length(p); for(int i=0; i < n; ++i) { pair z=point(p,i); - real[] T=intersections(p,z,z+I*dir(p,i)); + pair dir=dir(p,i); + if(dir == 0) continue; + real[] T=intersections(p,z,z+I*dir); // Check midpoints of line segments formed between the // corresponding intersection points and z. for(int j=0; j < T.length; ++j) { if(T[j] != i) { pair w=point(p,T[j]); pair m=0.5*(z+w); - if(inside(windingnumber(p,m),fillrule)) return m; + if(interior(windingnumber(p,m),fillrule)) return m; } } } - abort("cannot find an interior point"); - return 0; + // cannot find an interior point: path is degenerate + return point(p,0); } // Return all intersection times of path g with the vertical line through (x,0). diff --git a/Build/source/utils/asymptote/base/plain_pens.asy b/Build/source/utils/asymptote/base/plain_pens.asy index 003c79149c7..09993d44da8 100644 --- a/Build/source/utils/asymptote/base/plain_pens.asy +++ b/Build/source/utils/asymptote/base/plain_pens.asy @@ -25,7 +25,9 @@ restricted pen beveljoin=linejoin(2); restricted pen zerowinding=fillrule(0); restricted pen evenodd=fillrule(1); -bool inside(int windingnumber, pen fillrule) { + +bool interior(int windingnumber, pen fillrule) +{ return windingnumber != undefined && (fillrule(fillrule) == 1 ? windingnumber % 2 == 1 : windingnumber != 0); } @@ -351,5 +353,3 @@ pen[] mean(pen[][] palette, real opacity(real[])=min) return sequence(new pen(int i) {return mean(palette[i],opacity);}, palette.length); } - - diff --git a/Build/source/utils/asymptote/base/plain_strings.asy b/Build/source/utils/asymptote/base/plain_strings.asy index 801e63e83cf..e3d0a797d86 100644 --- a/Build/source/utils/asymptote/base/plain_strings.asy +++ b/Build/source/utils/asymptote/base/plain_strings.asy @@ -190,3 +190,22 @@ string phantom(string s) { return "\phantom{"+s+"}"; } + +restricted int ocgindex=0; + +void begin(picture pic=currentpicture, string name, string id="", + bool visible=true) +{ + if(!latex() || !pdf()) return; + settings.twice=true; + if(id == "") id=string(++ocgindex); + tex(pic,"\begin{ocg}{"+name+"}{"+id+"}{"+(visible ? "1" : "0")+"}"); + layer(pic); +} + +void end(picture pic=currentpicture) +{ + if(!latex() || !pdf()) return; + tex(pic,"\end{ocg}"); + layer(pic); +} diff --git a/Build/source/utils/asymptote/base/three.asy b/Build/source/utils/asymptote/base/three.asy index 8e0fab6e8d0..0af0d2c3bdf 100644 --- a/Build/source/utils/asymptote/base/three.asy +++ b/Build/source/utils/asymptote/base/three.asy @@ -3,10 +3,12 @@ private import math; if(inXasyMode) settings.render=0; if(prc0()) { - access embed; - Embed=embed.embed; - Link=embed.link; if(settings.tex == "context") settings.prc=false; + else { + access embed; + Embed=embed.embed; + Link=embed.link; + } } real defaultshininess=0.25; @@ -14,12 +16,12 @@ real defaultgranularity=0; real linegranularity=0.01; real tubegranularity=0.003; real dotgranularity=0.0001; -pair viewportmargin=0; // Horizontal and vertical viewport margins. -real viewportfactor=1.005; // Factor used to expand orthographic viewport. - -real angleprecision=1e-3; // Precision for centering perspective projections. +pair viewportmargin=0; // Horizontal and vertical viewport margins. +real viewportfactor=1.002; // Factor used to expand orthographic viewport. +real viewportpadding=1.2; // Offset used to expand PRC viewport. +real angleprecision=1e-3; // Precision for centering perspective projections. real anglefactor=max(1.005,1+angleprecision); - // Factor used to expand perspective viewport. +// Factor used to expand perspective viewport. string defaultembed3Doptions; string defaultembed3Dscript; @@ -1690,7 +1692,8 @@ transform3 transform3(projection P) triple v=unit(P.oblique ? P.camera : P.vector()); triple u=unit(perp(P.up,v)); if(u == O) u=cross(perp(v),v); - return transform3(cross(u,v),u); + v=cross(u,v); + return v != O ? transform3(v,u) : identity(4); } triple[] triples(real[] x, real[] y, real[] z) @@ -2203,7 +2206,7 @@ function asyProjection() {"+ (infinity ? "activeCamera.projectionType=activeCamera.TYPE_ORTHOGRAPHIC;" : "activeCamera.projectionType=activeCamera.TYPE_PERSPECTIVE;")+" activeCamera.viewPlaneSize="+string(viewplanesize)+"; -activeCamera.binding=activeCamera.BINDING_VERTICAL; +activeCamera.binding=activeCamera.BINDING_"+(infinity ? "MAX" : "VERTICAL")+"; } asyProjection(); @@ -2252,7 +2255,7 @@ void writeJavaScript(string name, string preamble, string script) file3.push(name); } -pair viewportmargin(projection P, real width, real height) +pair viewportmargin(real width, real height) { pair viewportmargin=viewportmargin; real xmargin=viewportmargin.x; @@ -2281,10 +2284,11 @@ string embed3D(string label="", string text=label, string prefix, real viewplanesize; if(P.infinity) { triple lambda=max3(f)-min3(f); - real margin=(viewportfactor-1.0)*lambda.y+ - viewportmargin(P,lambda.x,lambda.y).y; - viewplanesize=(lambda.y+2*margin)/cm; - } + pair margin=viewportpadding*(1,1)+viewportmargin(lambda.x,lambda.y); + viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/cm; + } else + if(!P.absolute) angle=2*aTan(Tan(0.5*angle)-viewportpadding/P.target.z); + string name=prefix+".js"; writeJavaScript(name,lightscript+projection(P.infinity,viewplanesize),script); @@ -2308,7 +2312,7 @@ string embed3D(string label="", string text=label, string prefix, if(defaultembed3Doptions != "") options3 += ","+defaultembed3Doptions; if((settings.render < 0 || !settings.embed) && settings.auto3D) options3 += ",poster"; - options3 += ",text="+text+",label="+label+ + options3 += ",text={"+text+"},label="+label+ ",toolbar="+(settings.toolbar ? "true" : "false")+ ",3Daac="+format(P.absolute ? P.angle : angle)+ ",3Dc2c="+format(u)+ @@ -2402,7 +2406,7 @@ object embed(string label="", string text=label, pair m2=pic2.min(s); pair M2=pic2.max(s); pair lambda=M2-m2; - pair viewportmargin=viewportmargin(P,lambda.x,lambda.y); + pair viewportmargin=viewportmargin(lambda.x,lambda.y); real width=ceil(lambda.x+2*viewportmargin.x); real height=ceil(lambda.y+2*viewportmargin.y); @@ -2435,6 +2439,11 @@ object embed(string label="", string text=label, if(P.infinity) { triple m=min3(f); triple M=max3(f); + triple lambda=M-m; + viewportmargin=viewportmargin(lambda.x,lambda.y); + width=lambda.x+2*viewportmargin.x; + height=lambda.y+2*viewportmargin.y; + triple s=(-0.5(m.x+M.x),-0.5*(m.y+M.y),0); f=shift(s)*f; // Eye will be at (0,0,0). } else { @@ -2513,13 +2522,14 @@ object embed(string label="", string text=label, if(P.absolute) { modelview=P.modelview(); f=modelview*f; - P=modelview*P; + Q=modelview*P; m=min3(f); M=max3(f); real r=0.5*abs(M-m); zcenter=0.5*(M.z+m.z); M=(M.x,M.y,zcenter+r); m=(m.x,m.y,zcenter-r); + angle=P.angle; } else { m=min3(f); M=max3(f); @@ -2530,9 +2540,9 @@ object embed(string label="", string text=label, } if(P.infinity) { - triple margin=(viewportfactor-1.0)*(abs(M.x-m.x), - abs(M.y-m.y),0)+ - viewportfactor*(0,viewportmargin.y,0); + triple margin=(viewportfactor-1.0)*(abs(M.x-m.x),abs(M.y-m.y),0) + +(viewportmargin.x,viewportmargin.y,0); + M += margin; m -= margin; } else if(M.z >= 0) abort("camera too close"); @@ -2552,11 +2562,10 @@ object embed(string label="", string text=label, if(settings.inlinetex) image += "_0"; image += "."+nativeformat(); if(!settings.inlinetex) file3.push(image); - image=graphic(image); + image=graphic(image,"hiresbb"); } if(prc) F.L=embed3D(label,text=image,prefix,f,format, - width,height,angle,options,script,light, - P.absolute ? P : Q); + width,height,angle,options,script,light,Q); } if(!is3D) { @@ -2600,27 +2609,60 @@ currentpicture.fitter=new frame(string prefix, picture pic, string format, if(currentlight.background != nullpen) box(f,currentlight.background,Fill,above=false); } else if(!view) - label(f,graphic(prefix)); + label(f,graphic(prefix,"hiresbb")); } } return f; }; void addViews(picture dest, picture src, bool group=true, - filltype filltype=NoFill, bool above=true) + filltype filltype=NoFill) { + if(group) begingroup(dest); frame Front=src.fit(FrontView); - add(dest,Front,group,filltype,above); + add(dest,Front,filltype); frame Top=src.fit(TopView); - add(dest,shift(0,min(Front).y-max(Top).y)*Top,group,filltype,above); + add(dest,shift(0,min(Front).y-max(Top).y)*Top,filltype); frame Right=src.fit(RightView); - add(dest,shift(min(Front).x-max(Right).x)*Right,group,filltype,above); + add(dest,shift(min(Front).x-max(Right).x)*Right,filltype); + if(group) endgroup(dest); +} + +void addViews(picture src, bool group=true, filltype filltype=NoFill) +{ + addViews(currentpicture,src,group,filltype); +} + +void addAllViews(picture dest, picture src, + real xmargin=0, real ymargin=xmargin, + bool group=true, + filltype filltype=NoFill) +{ + picture picL,picM,picR,picLM; + if(xmargin == 0) xmargin=sqrtEpsilon; + if(ymargin == 0) ymargin=sqrtEpsilon; + + add(picL,src.fit(FrontView),(0,0),ymargin*N); + add(picL,src.fit(BackView),(0,0),ymargin*S); + + add(picM,src.fit(TopView),(0,0),ymargin*N); + add(picM,src.fit(BottomView),(0,0),ymargin*S); + + add(picR,src.fit(RightView),(0,0),ymargin*N); + add(picR,src.fit(LeftView),(0,0),ymargin*S); + + add(picLM,picL.fit(),(0,0),xmargin*W); + add(picLM,picM.fit(),(0,0),xmargin*E); + + if(group) begingroup(dest); + add(dest,picLM.fit(),(0,0),xmargin*W,filltype); + add(dest,picR.fit(),(0,0),xmargin*E,filltype); + if(group) endgroup(dest); } -void addViews(picture src, bool group=true, filltype filltype=NoFill, - bool above=true) +void addAllViews(picture src, bool group=true, filltype filltype=NoFill) { - addViews(currentpicture,src,group,filltype,above); + addAllViews(currentpicture,src,group,filltype); } // Force an array of 3D pictures to be as least as large as picture all. diff --git a/Build/source/utils/asymptote/base/three_light.asy b/Build/source/utils/asymptote/base/three_light.asy index 54ca7a47151..8e5a6281795 100644 --- a/Build/source/utils/asymptote/base/three_light.asy +++ b/Build/source/utils/asymptote/base/three_light.asy @@ -82,42 +82,45 @@ struct light { pen background; // Background color of the 3D canvas. real specularfactor; bool viewport; // Are the lights specified (and fixed) in the viewport frame? - triple[] position; // Only directional lights are implemented. + triple[] position; // Only directional lights are currently implemented. transform3 T=identity(4); // Transform to apply to normal vectors. bool on() {return position.length > 0;} - void operator init(pen[] diffuse=array(position.length,white), - pen[] ambient=array(position.length,black), - pen[] specular=diffuse, pen background=nullpen, + void operator init(pen[] diffuse, + pen[] ambient=array(diffuse.length,black), + pen[] specular=diffuse, pen background=nullpen, real specularfactor=1, - bool viewport=true, triple[] position) { - this.position=new triple[position.length]; - this.diffuse=new real[position.length][]; - this.ambient=new real[position.length][]; - this.specular=new real[position.length][]; + bool viewport=true, triple[] position) { + int n=diffuse.length; + assert(ambient.length == n && specular.length == n && position.length == n); + + this.diffuse=new real[n][]; + this.ambient=new real[n][]; + this.specular=new real[n][]; this.background=background; + this.position=new triple[n]; for(int i=0; i < position.length; ++i) { - this.position[i]=unit(position[i]); this.diffuse[i]=rgba(diffuse[i]); this.ambient[i]=rgba(ambient[i]); this.specular[i]=rgba(specular[i]); + this.position[i]=unit(position[i]); } this.specularfactor=specularfactor; this.viewport=viewport; } void operator init(pen diffuse=white, pen ambient=black, pen specular=diffuse, - pen background=nullpen, real specularfactor=1, - bool viewport=true...triple[] position) { + pen background=nullpen, real specularfactor=1, + bool viewport=true...triple[] position) { int n=position.length; operator init(array(n,diffuse),array(n,ambient),array(n,specular), - background,specularfactor,viewport,position); + background,specularfactor,viewport,position); } void operator init(pen diffuse=white, pen ambient=black, pen specular=diffuse, - pen background=nullpen, bool viewport=true, + pen background=nullpen, bool viewport=true, real x, real y, real z) { operator init(diffuse,ambient,specular,background,viewport,(x,y,z)); } @@ -146,9 +149,9 @@ struct light { triple L=viewport ? position[i] : T*position[i]; real Ldotn=max(dot(normal,L),0); p += ambient[i]*Ambient+Ldotn*diffuse[i]*Diffuse; -// Apply specularfactor to partially compensate non-pixel-based rendering. + // Apply specularfactor to partially compensate non-pixel-based rendering. if(Ldotn > 0) // Phong-Blinn model of specular reflection - p += dot(normal,unit(L+Z))^s*specularfactor*specular[i]*Specular; + p += dot(normal,unit(L+Z))^s*specularfactor*specular[i]*Specular; } return rgb(p[0],p[1],p[2])+opacity(opacity(m.diffuse())); } @@ -165,10 +168,14 @@ light operator * (transform3 t, light light) light operator cast(triple v) {return light(v);} -light currentlight=light(ambient=rgb(0.1,0.1,0.1),specularfactor=3, +light currentlight=light(ambient=gray(0.1),specularfactor=3, (0.25,-0.25,1)); -light adobe=light(gray(0.4),specularfactor=3,viewport=false, - (0.5,-0.5,-0.25),(0.5,0.5,0.25), - (0.5,-0.5,0.2),(-0.5,0.5,-0.2)); +light White=light(new pen[] {rgb(0.38,0.38,0.45),rgb(0.6,0.6,0.67), + rgb(0.5,0.5,0.57)},specularfactor=3,viewport=false, + new triple[] {(-2,-1.5,-0.5),(2,1.1,-2.5),(-0.5,0,2)}); + +light Headlamp=light(gray(0.9),ambient=gray(0.1),specularfactor=3, + (0.5,0.5,1/sqrt(2)),specular=gray(0.7)); + light nolight; diff --git a/Build/source/utils/asymptote/base/three_surface.asy b/Build/source/utils/asymptote/base/three_surface.asy index 55060cb516d..3c49b382133 100644 --- a/Build/source/utils/asymptote/base/three_surface.asy +++ b/Build/source/utils/asymptote/base/three_surface.asy @@ -681,6 +681,22 @@ struct surface { 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. + if(external.length != 0) { + triple n=normal(external[0]); + if(n != O) { + transform3 T=align(n); + external=transpose(T)*external; + T *= shift(0,0,point(external[0],0).z); + path[] g=sequence(new path(int i) {return path(external[i]);}, + external.length); + for(patch p : surface(g).s) + s.push(T*p); + return; + } + } + } + for(int i=0; i < external.length; ++i) construct(external[i], internal.length == 0 ? new triple[] : internal[i], -- cgit v1.2.3