summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/base
diff options
context:
space:
mode:
Diffstat (limited to 'Build/source/utils/asymptote/base')
-rw-r--r--Build/source/utils/asymptote/base/bezulate.asy78
-rw-r--r--Build/source/utils/asymptote/base/embed.asy4
-rw-r--r--Build/source/utils/asymptote/base/geometry.asy2
-rw-r--r--Build/source/utils/asymptote/base/graph3.asy155
-rw-r--r--Build/source/utils/asymptote/base/labelpath3.asy4
-rw-r--r--Build/source/utils/asymptote/base/lmfit.asy28
-rw-r--r--Build/source/utils/asymptote/base/math.asy30
-rw-r--r--Build/source/utils/asymptote/base/plain_arrows.asy24
-rw-r--r--Build/source/utils/asymptote/base/solids.asy5
-rw-r--r--Build/source/utils/asymptote/base/three.asy295
-rw-r--r--Build/source/utils/asymptote/base/three_arrows.asy2
-rw-r--r--Build/source/utils/asymptote/base/three_light.asy17
-rw-r--r--Build/source/utils/asymptote/base/three_surface.asy252
-rw-r--r--Build/source/utils/asymptote/base/three_tube.asy223
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));
}
}