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/bsp.asy6
-rw-r--r--Build/source/utils/asymptote/base/embed.asy4
-rw-r--r--Build/source/utils/asymptote/base/flowchart.asy8
-rw-r--r--Build/source/utils/asymptote/base/geometry.asy104
-rw-r--r--Build/source/utils/asymptote/base/graph.asy130
-rw-r--r--Build/source/utils/asymptote/base/graph3.asy132
-rw-r--r--Build/source/utils/asymptote/base/grid3.asy48
-rw-r--r--Build/source/utils/asymptote/base/math.asy27
-rw-r--r--Build/source/utils/asymptote/base/palette.asy12
-rw-r--r--Build/source/utils/asymptote/base/plain_arrows.asy115
-rw-r--r--Build/source/utils/asymptote/base/plain_bounds.asy783
-rw-r--r--Build/source/utils/asymptote/base/plain_constants.asy2
-rw-r--r--Build/source/utils/asymptote/base/plain_pens.asy6
-rw-r--r--Build/source/utils/asymptote/base/plain_picture.asy1118
-rw-r--r--Build/source/utils/asymptote/base/plain_prethree.asy224
-rw-r--r--Build/source/utils/asymptote/base/plain_scaling.asy246
-rw-r--r--Build/source/utils/asymptote/base/plain_shipout.asy16
-rw-r--r--Build/source/utils/asymptote/base/plain_strings.asy20
-rw-r--r--Build/source/utils/asymptote/base/plain_xasy.asy6
-rw-r--r--Build/source/utils/asymptote/base/simplex.asy6
-rw-r--r--Build/source/utils/asymptote/base/slide.asy21
-rw-r--r--Build/source/utils/asymptote/base/solids.asy1
-rw-r--r--Build/source/utils/asymptote/base/three.asy24
-rw-r--r--Build/source/utils/asymptote/base/three_surface.asy26
-rw-r--r--Build/source/utils/asymptote/base/trembling.asy492
25 files changed, 2224 insertions, 1353 deletions
diff --git a/Build/source/utils/asymptote/base/bsp.asy b/Build/source/utils/asymptote/base/bsp.asy
index a744da522cc..2a4d93daa81 100644
--- a/Build/source/utils/asymptote/base/bsp.asy
+++ b/Build/source/utils/asymptote/base/bsp.asy
@@ -201,7 +201,9 @@ void add(picture pic=currentpicture, face[] faces,
for(int i=0; i < n; ++i) {
picture F=Faces[i].pic;
- pic.userBox(F.userMin,F.userMax);
- pic.append(pic.bounds.point,pic.bounds.min,pic.bounds.max,F.T,F.bounds);
+ pic.userBox3(F.userMin3(), F.userMax3());
+ pic.bounds.append(F.T, F.bounds);
+ // The above 2 lines should be replaced with a routine in picture which
+ // copies only sizing data from another picture.
}
}
diff --git a/Build/source/utils/asymptote/base/embed.asy b/Build/source/utils/asymptote/base/embed.asy
index dc6c7d4101a..165de0b7534 100644
--- a/Build/source/utils/asymptote/base/embed.asy
+++ b/Build/source/utils/asymptote/base/embed.asy
@@ -6,7 +6,9 @@ if(latex()) {
\usepackage[3D,dvipdfmx]{movie15}
\else%
\usepackage[3D]{movie15}
-\fi%");
+\fi%
+\FPmessagesfalse%
+");
}
// See http://www.ctan.org/tex-archive/macros/latex/contrib/movie15/README
diff --git a/Build/source/utils/asymptote/base/flowchart.asy b/Build/source/utils/asymptote/base/flowchart.asy
index bb8fe21a4d6..3db66173755 100644
--- a/Build/source/utils/asymptote/base/flowchart.asy
+++ b/Build/source/utils/asymptote/base/flowchart.asy
@@ -424,20 +424,20 @@ blockconnector blockconnector(picture pic, transform t, pen p=currentpen,
if(abs(b1.center.y-b2.center.y) < sqrtEpsilon) {
// horizontally aligned
b1.dirs[0]=b1.center.x < b2.center.x ? right : left;
- blockconnector(pic,t)(b1,b2);
+ blockconnector(pic,t,p,margin)(b1,b2);
} else if(abs(b1.center.x-b2.center.x) < sqrtEpsilon) {
// vertically aligned
b1.dirs[0]=b1.center.y < b2.center.y ? up : down;
- blockconnector(pic,t)(b1,b2);
+ blockconnector(pic,t,p,margin)(b1,b2);
} else {
if(abs(b1.center.y-b2.center.y) < abs(b1.center.x-b2.center.x)) {
b1.dirs[0]=b1.center.x < b2.center.x ? right : left;
b1.dirs[1]=b1.center.y < b2.center.y ? up : down;
- blockconnector(pic,t)(b1,b2);
+ blockconnector(pic,t,p,margin)(b1,b2);
} else {
b1.dirs[0]=b1.center.y < b2.center.y ? up : down;
b1.dirs[1]=b1.center.x < b2.center.x ? right : left;
- blockconnector(pic,t)(b1,b2);
+ blockconnector(pic,t,p,margin)(b1,b2);
}
}
return b2;
diff --git a/Build/source/utils/asymptote/base/geometry.asy b/Build/source/utils/asymptote/base/geometry.asy
index 41a6397de64..61ff1ba8e8f 100644
--- a/Build/source/utils/asymptote/base/geometry.asy
+++ b/Build/source/utils/asymptote/base/geometry.asy
@@ -433,10 +433,6 @@ point point(explicit pair p, real m)
op.init(currentcoordsys, p, m);
return op;
}
-point point(explicit pair p, int m)
-{// Handle ambiguity
- return point(p,(real)m);
-}
/*<asyxml><function type="point" signature="point(coordsys,explicit point,real)"><code></asyxml>*/
point point(coordsys R, explicit point M, real m=M.m)
@@ -1150,17 +1146,18 @@ private void Drawline(picture pic=currentpicture, Label L="",pair P, bool dirP=t
Label legend="", marker marker=nomarker,
pathModifier pathModifier=NoModifier)
{/* Add the two parameters 'dirP' and 'dirQ' to the native routine
- 'drawline' of the module 'maths'.
+ 'drawline' of the module 'math'.
Segment [PQ] will be prolonged in direction of P if 'dirP=true', in
direction of Q if 'dirQ=true'.
If 'dirP=dirQ=true', the behavior is that of the native 'drawline'.
Add all the other parameters of 'Draw'.*/
- pic.add(new void (frame f, transform t, transform, pair m, pair M) {
+ pic.add(new void (frame f, transform t, transform T, pair m, pair M) {
picture opic;
// Reduce the bounds by the size of the pen.
m -= min(p)-(linemargin(),linemargin()); M -= max(p)+(linemargin(),linemargin());
// Calculate the points and direction vector in the transformed space.
+ t=t*T;
pair z=t*P;
pair q=t*Q;
pair v=q-z;
@@ -1175,16 +1172,16 @@ private void Drawline(picture pic=currentpicture, Label L="",pair P, bool dirP=t
ptp=(z.x,z.y+cp*(m.y-z.y));
ptq=(z.x,q.y+cq*(M.y-q.y));
} else {
- ptp=(z.x,q.y+cq*(m.y-q.y));
- ptq=(z.x,z.y+cp*(M.y-z.y));
+ ptq=(z.x,q.y+cq*(m.y-q.y));
+ ptp=(z.x,z.y+cp*(M.y-z.y));
}
} else if(v.y == 0) {
if (dot(v,m-z) < 0) {
ptp=(z.x+cp*(m.x-z.x),z.y);
ptq=(q.x+cq*(M.x-q.x),z.y);
} else {
- ptp=(q.x+cq*(m.x-q.x),z.y);
- ptq=(z.x+cp*(M.x-z.x),z.y);
+ ptq=(q.x+cq*(m.x-q.x),z.y);
+ ptp=(z.x+cp*(M.x-z.x),z.y);
}
} else {
// Calculate the maximum and minimum t values allowed for the
@@ -1239,12 +1236,12 @@ void clipdraw(picture pic=currentpicture, Label L="", path g,
label(tmp,L,g,p);
add(pic,tmp);
}
- pic.add(new void (frame f, transform t, transform, pair m, pair M) {
+ pic.add(new void (frame f, transform t, transform T, pair m, pair M) {
// Reduce the bounds by the size of the pen and the margins.
m += min(p)+(xmargin,ymargin); M -= max(p)+(xmargin,ymargin);
path bound=box(m,M);
picture tmp;
- draw(tmp,"",t*g,align,p,arrow,bar,NoMargin,legend,marker);
+ draw(tmp,"",t*T*g,align,p,arrow,bar,NoMargin,legend,marker);
clip(tmp,bound);
add(f,tmp.fit());
});
@@ -2963,13 +2960,6 @@ ellipse ellipse(point C, real a, real b, real angle=0)
return oe;
}
-/*<asyxml><function type="ellipse" signature="ellipse(explicit pair,real,real)"><code></asyxml>*/
-ellipse ellipse(explicit pair C, real a, real b)=
- new ellipse(explicit pair C, real a, real b)
-{/*<asyxml></code><documentation>Overwrite the default routine.</documentation></function></asyxml>*/
- return ellipse((point)C,a,b,0);
-};
-
/*<asyxml><function type="ellipse" signature="ellipse(bqe)"><code></asyxml>*/
ellipse ellipse(bqe bqe)
{/*<asyxml></code><documentation>Return the ellipse a[0]*x^2 + a[1]*xy + a[2]*y^2 + a[3]*x + a[4]*y + a[5]=0
@@ -3204,16 +3194,6 @@ circle circle(explicit point C, real r)
if(!finite(r)) oc.l=line(C,C+vector(C.coordsys,(1,0)));
return oc;
}
-circle circle(explicit point C, int r)
-{
- return circle(C,(real) r);
-}
-
-/*<asyxml><function type="circle" signature="circle(pair,real)"><code></asyxml>*/
-circle circle(pair c, real r)=new circle(pair c, real r)
-{/*<asyxml></code><documentation>Overwrite 'circle(pair,real)'</documentation></function></asyxml>*/
- return circle(locate(c),r);
-};
/*<asyxml><function type="circle" signature="circle(point,point)"><code></asyxml>*/
circle circle(point A, point B)
@@ -3526,18 +3506,30 @@ path arcfromcenter(ellipse el, real angle1, real angle2,
The angles are mesured relatively to the axis (C,x-axis) where C is
the center of the ellipse.</documentation></function></asyxml>*/
if(degenerate(el)) abort("arcfromcenter: can not convert degenerated ellipse to path.");
- guide op;
- coordsys Rp=coordsys(el);
- if (n < 1) return op;
if (angle1 > angle2)
return reverse(arcfromcenter(el,angle2,angle1,!direction,n));
+ path op;
+ coordsys Rp=coordsys(el);
+ if (n < 1) return op;
+ interpolate join = operator ..;
+ real stretch = max(el.a/el.b, el.b/el.a);
+ if (stretch > 10) {
+ n *= floor(stretch/5);
+ join=operator --;
+ }
real a1=direction ? radians(angle1) : radians(angle2);
real a2=direction ? radians(angle2) : radians(angle1)+2*pi;
real step=(a2-a1)/(n != 1 ? n-1 : 1);
real a,r;
real da=radians(el.angle);
+ real a3=angle((cos(a1)/el.a,sin(a1)/el.b));
+ real a3=(a3>=0) ? a3 : a3+2pi;
+ real a4=angle((cos(a2)/el.a,sin(a2)/el.b));
+ real a4=(a4>=0) ? a4 : a4+2pi;
+ real step=(a4-a3)/(n != 1 ? n-1 : 1);
for (int i=0; i < n; ++i) {
- a=a1+i*step;
+ a=a3+i*step;
+ a=angle((el.a*cos(a),el.b*sin(a)));
r=el.b/sqrt(1-(el.e*cos(a))^2);
op=op..Rp*Rp.polar(r,a+da);
}
@@ -3782,16 +3774,17 @@ void draw(picture pic=currentpicture, Label L="",parabola parabola,
margin margin=NoMargin, Label legend="", marker marker=nomarker)
{/*<asyxml></code><documentation>Draw the parabola 'p' on 'pic' without (if possible) altering the
size of picture pic.</documentation></function></asyxml>*/
- pic.add(new void (frame f, transform t, transform, pair m, pair M) {
+ pic.add(new void (frame f, transform t, transform T, pair m, pair M) {
// Reduce the bounds by the size of the pen and the margins.
m -= min(p); M -= max(p);
parabola.bmin=inverse(t)*m; parabola.bmax=inverse(t)*M;
picture tmp;
- draw(tmp,L,t*(path) parabola,align,p,arrow,bar,NoMargin,legend,marker);
+ draw(tmp,L,t*T*(path) parabola,align,p,arrow,bar,NoMargin,legend,marker);
add(f,tmp.fit());
});
- if(pic.userMin.x != pic.userMax.x & pic.userMin.y != pic.userMax.y &
- !finite(abs(pic.userMin)) & !finite(abs(pic.userMax)))
+ pair m=pic.userMin();
+ pair M=pic.userMax();
+ if(m != M)
pic.addBox(truepoint(SW), truepoint(NE));
}
@@ -3814,19 +3807,21 @@ void draw(picture pic=currentpicture, Label L="", hyperbola h,
margin margin=NoMargin, Label legend="", marker marker=nomarker)
{/*<asyxml></code><documentation>Draw the hyperbola 'h' on 'pic' without (if possible) altering the
size of the picture pic.</documentation></function></asyxml>*/
- pic.add(new void (frame f, transform t, transform, pair m, pair M) {
+ pic.add(new void (frame f, transform t, transform T, pair m, pair M) {
// Reduce the bounds by the size of the pen and the margins.
m -= min(p); M -= max(p);
h.bmin=inverse(t)*m; h.bmax=inverse(t)*M;
picture tmp;
- draw(tmp,L,t*(path) h,align,p,arrow,bar,NoMargin,legend,marker);
+ transform tT=t*T;
+ draw(tmp,L,tT*(path) h,align,p,arrow,bar,NoMargin,legend,marker);
hyperbola ht=hyperbola(h.F2,h.F1,h.a);
ht.bmin=inverse(t)*m; ht.bmax=inverse(t)*M;
- draw(tmp,"",t*(path) ht,align,p,arrow,bar,NoMargin,marker);
+ draw(tmp,"",tT*(path) ht,align,p,arrow,bar,NoMargin,marker);
add(f,tmp.fit());
});
- if(pic.userMin.x != pic.userMax.x & pic.userMin.y != pic.userMax.y &
- !finite(abs(pic.userMin)) & !finite(abs(pic.userMax)))
+ pair m=pic.userMin();
+ pair M=pic.userMax();
+ if(m != M)
pic.addBox(truepoint(SW), truepoint(NE));
}
@@ -4158,10 +4153,6 @@ abscissa operator +(int x, explicit abscissa a)
{
return ((real)x)+a;
}
-abscissa operator +(explicit abscissa a, int x)
-{
- return ((real)x)+a;
-}
/*<asyxml><operator type="abscissa" signature="-(explicit abscissa a)"><code></asyxml>*/
abscissa operator -(explicit abscissa a)
@@ -4190,10 +4181,6 @@ abscissa operator -(int x, explicit abscissa a)
{
return ((real)x)-a;
}
-abscissa operator -(explicit abscissa a, int x)
-{
- return a-((real)x);
-}
/*<asyxml><operator type="abscissa" signature="*(real,abscissa)"><code></asyxml>*/
abscissa operator *(real x, explicit abscissa a)
@@ -4210,15 +4197,6 @@ abscissa operator *(explicit abscissa a, real x)
return x*a;
}
-abscissa operator *(int x, explicit abscissa a)
-{
- return ((real)x)*a;
-}
-abscissa operator *(explicit abscissa a, int x)
-{
- return ((real)x)*a;
-}
-
abscissa operator /(real x, explicit abscissa a)
{
abscissa oa;
@@ -4238,10 +4216,6 @@ abscissa operator /(int x, explicit abscissa a)
{
return ((real)x)/a;
}
-abscissa operator /(explicit abscissa a, int x)
-{
- return a/((real)x);
-}
/*<asyxml><function type="abscissa" signature="relabscissa(real)"><code></asyxml>*/
abscissa relabscissa(real x)
@@ -4832,6 +4806,10 @@ struct arc {
/*<asyxml><method type="void" signature="setangles(real,real,real)"><code></asyxml>*/
void setangles(real a0, real a1, real a2)
{/*<asyxml></code><documentation>Set the angles.</documentation></method></asyxml>*/
+ if (a1 < 0 && a2 < 0) {
+ a1 += 360;
+ a2 += 360;
+ }
this.angle0=a0%(sgnd(a0)*360);
this.angle1=a1%(sgnd(a1)*360);
this.angle2=a2%(sgnd(2)*360);
diff --git a/Build/source/utils/asymptote/base/graph.asy b/Build/source/utils/asymptote/base/graph.asy
index 9ac9983ddef..a7ffabc6220 100644
--- a/Build/source/utils/asymptote/base/graph.asy
+++ b/Build/source/utils/asymptote/base/graph.asy
@@ -1203,17 +1203,17 @@ void xaxisAt(picture pic=currentpicture, Label L="", axis axis,
void bounds() {
if(type == Min)
- y=pic.scale.y.automin() ? tickMin(pic).y : pic.userMin.y;
+ y=pic.scale.y.automin() ? tickMin(pic).y : pic.userMin().y;
else if(type == Max)
- y=pic.scale.y.automax() ? tickMax(pic).y : pic.userMax.y;
+ y=pic.scale.y.automax() ? tickMax(pic).y : pic.userMax().y;
else if(type == Both) {
- y2=pic.scale.y.automax() ? tickMax(pic).y : pic.userMax.y;
+ y2=pic.scale.y.automax() ? tickMax(pic).y : pic.userMax().y;
y=opposite ? y2 :
- (pic.scale.y.automin() ? tickMin(pic).y : pic.userMin.y);
+ (pic.scale.y.automin() ? tickMin(pic).y : pic.userMin().y);
}
- real Xmin=finite(xmin) ? xmin : pic.userMin.x;
- real Xmax=finite(xmax) ? xmax : pic.userMax.x;
+ real Xmin=finite(xmin) ? xmin : pic.userMin().x;
+ real Xmax=finite(xmax) ? xmax : pic.userMax().x;
pair a=(Xmin,y);
pair b=(Xmax,y);
@@ -1297,17 +1297,17 @@ void yaxisAt(picture pic=currentpicture, Label L="", axis axis,
void bounds() {
if(type == Min)
- x=pic.scale.x.automin() ? tickMin(pic).x : pic.userMin.x;
+ x=pic.scale.x.automin() ? tickMin(pic).x : pic.userMin().x;
else if(type == Max)
- x=pic.scale.x.automax() ? tickMax(pic).x : pic.userMax.x;
+ x=pic.scale.x.automax() ? tickMax(pic).x : pic.userMax().x;
else if(type == Both) {
- x2=pic.scale.x.automax() ? tickMax(pic).x : pic.userMax.x;
+ x2=pic.scale.x.automax() ? tickMax(pic).x : pic.userMax().x;
x=opposite ? x2 :
- (pic.scale.x.automin() ? tickMin(pic).x : pic.userMin.x);
+ (pic.scale.x.automin() ? tickMin(pic).x : pic.userMin().x);
}
- real Ymin=finite(ymin) ? ymin : pic.userMin.y;
- real Ymax=finite(ymax) ? ymax : pic.userMax.y;
+ real Ymin=finite(ymin) ? ymin : pic.userMin().y;
+ real Ymax=finite(ymax) ? ymax : pic.userMax().y;
pair a=(x,Ymin);
pair b=(x,Ymax);
@@ -1363,21 +1363,22 @@ void xlimits(picture pic=currentpicture, real min=-infinity, real max=infinity,
bounds mx;
if(pic.scale.x.automin() || pic.scale.x.automax())
- mx=autoscale(pic.userMin.x,pic.userMax.x,pic.scale.x.scale);
+ mx=autoscale(pic.userMin().x,pic.userMax().x,pic.scale.x.scale);
if(pic.scale.x.automin) {
if(pic.scale.x.automin()) pic.userMinx(mx.min);
- } else pic.userMinx(pic.scale.x.T(min));
+ } else pic.userMinx(min(pic.scale.x.T(min),pic.scale.x.T(max)));
if(pic.scale.x.automax) {
if(pic.scale.x.automax()) pic.userMaxx(mx.max);
- } else pic.userMaxx(pic.scale.x.T(max));
+ } else pic.userMaxx(max(pic.scale.x.T(min),pic.scale.x.T(max)));
if(crop) {
pair userMin=pic.userMin();
pair userMax=pic.userMax();
pic.bounds.xclip(userMin.x,userMax.x);
- pic.clip(new void (frame f, transform t, transform T, pair, pair) {
+ pic.clip(userMin, userMax,
+ new void (frame f, transform t, transform T, pair, pair) {
frame Tinvf=T == identity() ? f : t*inverse(T)*inverse(t)*f;
clip(f,T*box(((t*userMin).x,(min(Tinvf)).y),
((t*userMax).x,(max(Tinvf)).y)));
@@ -1396,21 +1397,22 @@ void ylimits(picture pic=currentpicture, real min=-infinity, real max=infinity,
bounds my;
if(pic.scale.y.automin() || pic.scale.y.automax())
- my=autoscale(pic.userMin.y,pic.userMax.y,pic.scale.y.scale);
+ my=autoscale(pic.userMin().y,pic.userMax().y,pic.scale.y.scale);
if(pic.scale.y.automin) {
if(pic.scale.y.automin()) pic.userMiny(my.min);
- } else pic.userMiny(pic.scale.y.T(min));
+ } else pic.userMiny(min(pic.scale.y.T(min),pic.scale.y.T(max)));
if(pic.scale.y.automax) {
if(pic.scale.y.automax()) pic.userMaxy(my.max);
- } else pic.userMaxy(pic.scale.y.T(max));
+ } else pic.userMaxy(max(pic.scale.y.T(min),pic.scale.y.T(max)));
if(crop) {
pair userMin=pic.userMin();
pair userMax=pic.userMax();
pic.bounds.yclip(userMin.y,userMax.y);
- pic.clip(new void (frame f, transform t, transform T, pair, pair) {
+ pic.clip(userMin, userMax,
+ new void (frame f, transform t, transform T, pair, pair) {
frame Tinvf=T == identity() ? f : t*inverse(T)*inverse(t)*f;
clip(f,T*box(((min(Tinvf)).x,(t*userMin).y),
((max(Tinvf)).x,(t*userMax).y)));
@@ -1423,7 +1425,7 @@ void crop(picture pic=currentpicture)
{
xlimits(pic,false);
ylimits(pic,false);
- if(pic.userSetx && pic.userSety)
+ if(pic.userSetx() && pic.userSety())
clip(pic,box(pic.userMin(),pic.userMax()));
}
@@ -1432,7 +1434,7 @@ void limits(picture pic=currentpicture, pair min, pair max, bool crop=NoCrop)
{
xlimits(pic,min.x,max.x);
ylimits(pic,min.y,max.y);
- if(crop && pic.userSetx && pic.userSety)
+ if(crop && pic.userSetx() && pic.userSety())
clip(pic,box(pic.userMin(),pic.userMax()));
}
@@ -1443,25 +1445,25 @@ void autoscale(picture pic=currentpicture, axis axis)
bounds mx,my;
pic.scale.set=true;
- if(pic.userSetx) {
- mx=autoscale(pic.userMin.x,pic.userMax.x,pic.scale.x.scale);
+ if(pic.userSetx()) {
+ mx=autoscale(pic.userMin().x,pic.userMax().x,pic.scale.x.scale);
if(pic.scale.x.scale.logarithmic &&
- floor(pic.userMin.x) == floor(pic.userMax.x)) {
+ floor(pic.userMin().x) == floor(pic.userMax().x)) {
if(pic.scale.x.automin())
- pic.userMinx(floor(pic.userMin.x));
+ pic.userMinx(floor(pic.userMin().x));
if(pic.scale.x.automax())
- pic.userMaxx(ceil(pic.userMax.x));
+ pic.userMaxx(ceil(pic.userMax().x));
}
} else {mx.min=mx.max=0; pic.scale.set=false;}
- if(pic.userSety) {
- my=autoscale(pic.userMin.y,pic.userMax.y,pic.scale.y.scale);
+ if(pic.userSety()) {
+ my=autoscale(pic.userMin().y,pic.userMax().y,pic.scale.y.scale);
if(pic.scale.y.scale.logarithmic &&
- floor(pic.userMin.y) == floor(pic.userMax.y)) {
+ floor(pic.userMin().y) == floor(pic.userMax().y)) {
if(pic.scale.y.automin())
- pic.userMiny(floor(pic.userMin.y));
+ pic.userMiny(floor(pic.userMin().y));
if(pic.scale.y.automax())
- pic.userMaxy(ceil(pic.userMax.y));
+ pic.userMaxy(ceil(pic.userMax().y));
}
} else {my.min=my.max=0; pic.scale.set=false;}
@@ -1503,9 +1505,9 @@ void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero,
newticks=true;
}
- if(newticks && pic.userSetx && ticks != NoTicks) {
- if(xmin == -infinity) xmin=pic.userMin.x;
- if(xmax == infinity) xmax=pic.userMax.x;
+ if(newticks && pic.userSetx() && ticks != NoTicks) {
+ if(xmin == -infinity) xmin=pic.userMin().x;
+ if(xmax == infinity) xmax=pic.userMax().x;
bounds mx=autoscale(xmin,xmax,pic.scale.x.scale);
pic.scale.x.tickMin=mx.min;
pic.scale.x.tickMax=mx.max;
@@ -1517,15 +1519,15 @@ void xaxis(picture pic=currentpicture, Label L="", axis axis=YZero,
if(xmin == -infinity && !axis.extend) {
if(pic.scale.set)
xmin=pic.scale.x.automin() ? pic.scale.x.tickMin :
- max(pic.scale.x.tickMin,pic.userMin.x);
- else xmin=pic.userMin.x;
+ max(pic.scale.x.tickMin,pic.userMin().x);
+ else xmin=pic.userMin().x;
}
if(xmax == infinity && !axis.extend) {
if(pic.scale.set)
xmax=pic.scale.x.automax() ? pic.scale.x.tickMax :
- min(pic.scale.x.tickMax,pic.userMax.x);
- else xmax=pic.userMax.x;
+ min(pic.scale.x.tickMax,pic.userMax().x);
+ else xmax=pic.userMax().x;
}
if(L.defaultposition) L.position(axis.position);
@@ -1565,9 +1567,9 @@ void yaxis(picture pic=currentpicture, Label L="", axis axis=XZero,
newticks=true;
}
- if(newticks && pic.userSety && ticks != NoTicks) {
- if(ymin == -infinity) ymin=pic.userMin.y;
- if(ymax == infinity) ymax=pic.userMax.y;
+ if(newticks && pic.userSety() && ticks != NoTicks) {
+ if(ymin == -infinity) ymin=pic.userMin().y;
+ if(ymax == infinity) ymax=pic.userMax().y;
bounds my=autoscale(ymin,ymax,pic.scale.y.scale);
pic.scale.y.tickMin=my.min;
pic.scale.y.tickMax=my.max;
@@ -1579,16 +1581,16 @@ void yaxis(picture pic=currentpicture, Label L="", axis axis=XZero,
if(ymin == -infinity && !axis.extend) {
if(pic.scale.set)
ymin=pic.scale.y.automin() ? pic.scale.y.tickMin :
- max(pic.scale.y.tickMin,pic.userMin.y);
- else ymin=pic.userMin.y;
+ max(pic.scale.y.tickMin,pic.userMin().y);
+ else ymin=pic.userMin().y;
}
if(ymax == infinity && !axis.extend) {
if(pic.scale.set)
ymax=pic.scale.y.automax() ? pic.scale.y.tickMax :
- min(pic.scale.y.tickMax,pic.userMax.y);
- else ymax=pic.userMax.y;
+ min(pic.scale.y.tickMax,pic.userMax().y);
+ else ymax=pic.userMax().y;
}
if(L.defaultposition) L.position(axis.position);
@@ -1784,23 +1786,23 @@ picture secondaryX(picture primary=currentpicture, void f(picture))
{
if(!primary.scale.set) abort(noprimary);
picture pic;
- if(primary.userMax.x == primary.userMin.x) return pic;
+ if(primary.userMax().x == primary.userMin().x) return pic;
f(pic);
- if(!pic.userSetx) return pic;
- bounds a=autoscale(pic.userMin.x,pic.userMax.x,pic.scale.x.scale);
- real bmin=pic.scale.x.automin() ? a.min : pic.userMin.x;
- real bmax=pic.scale.x.automax() ? a.max : pic.userMax.x;
+ if(!pic.userSetx()) return pic;
+ bounds a=autoscale(pic.userMin().x,pic.userMax().x,pic.scale.x.scale);
+ real bmin=pic.scale.x.automin() ? a.min : pic.userMin().x;
+ real bmax=pic.scale.x.automax() ? a.max : pic.userMax().x;
real denom=bmax-bmin;
if(denom != 0) {
pic.erase();
- real m=(primary.userMax.x-primary.userMin.x)/denom;
- pic.scale.x.postscale=Linear(m,bmin-primary.userMin.x/m);
+ real m=(primary.userMax().x-primary.userMin().x)/denom;
+ pic.scale.x.postscale=Linear(m,bmin-primary.userMin().x/m);
pic.scale.set=true;
pic.scale.x.tickMin=pic.scale.x.postscale.T(a.min);
pic.scale.x.tickMax=pic.scale.x.postscale.T(a.max);
- pic.scale.y.tickMin=primary.userMin.y;
- pic.scale.y.tickMax=primary.userMax.y;
+ pic.scale.y.tickMin=primary.userMin().y;
+ pic.scale.y.tickMax=primary.userMax().y;
axis.xdivisor=a.divisor;
f(pic);
}
@@ -1813,21 +1815,21 @@ picture secondaryY(picture primary=currentpicture, void f(picture))
{
if(!primary.scale.set) abort(noprimary);
picture pic;
- if(primary.userMax.y == primary.userMin.y) return pic;
+ if(primary.userMax().y == primary.userMin().y) return pic;
f(pic);
- if(!pic.userSety) return pic;
- bounds a=autoscale(pic.userMin.y,pic.userMax.y,pic.scale.y.scale);
- real bmin=pic.scale.y.automin() ? a.min : pic.userMin.y;
- real bmax=pic.scale.y.automax() ? a.max : pic.userMax.y;
+ if(!pic.userSety()) return pic;
+ bounds a=autoscale(pic.userMin().y,pic.userMax().y,pic.scale.y.scale);
+ real bmin=pic.scale.y.automin() ? a.min : pic.userMin().y;
+ real bmax=pic.scale.y.automax() ? a.max : pic.userMax().y;
real denom=bmax-bmin;
if(denom != 0) {
pic.erase();
- real m=(primary.userMax.y-primary.userMin.y)/denom;
- pic.scale.y.postscale=Linear(m,bmin-primary.userMin.y/m);
+ real m=(primary.userMax().y-primary.userMin().y)/denom;
+ pic.scale.y.postscale=Linear(m,bmin-primary.userMin().y/m);
pic.scale.set=true;
- pic.scale.x.tickMin=primary.userMin.x;
- pic.scale.x.tickMax=primary.userMax.x;
+ pic.scale.x.tickMin=primary.userMin().x;
+ pic.scale.x.tickMax=primary.userMax().x;
pic.scale.y.tickMin=pic.scale.y.postscale.T(a.min);
pic.scale.y.tickMax=pic.scale.y.postscale.T(a.max);
axis.ydivisor=a.divisor;
diff --git a/Build/source/utils/asymptote/base/graph3.asy b/Build/source/utils/asymptote/base/graph3.asy
index e588c8aa4d6..391b72ca87a 100644
--- a/Build/source/utils/asymptote/base/graph3.asy
+++ b/Build/source/utils/asymptote/base/graph3.asy
@@ -363,14 +363,14 @@ InOutTicks=InOutTicks();
triple tickMin3(picture pic)
{
- return minbound(pic.userMin,(pic.scale.x.tickMin,pic.scale.y.tickMin,
- pic.scale.z.tickMin));
+ return minbound(pic.userMin(),(pic.scale.x.tickMin,pic.scale.y.tickMin,
+ pic.scale.z.tickMin));
}
triple tickMax3(picture pic)
{
- return maxbound(pic.userMax,(pic.scale.x.tickMax,pic.scale.y.tickMax,
- pic.scale.z.tickMax));
+ return maxbound(pic.userMax(),(pic.scale.x.tickMax,pic.scale.y.tickMax,
+ pic.scale.z.tickMax));
}
axis Bounds(int type=Both, int type2=Both, triple align=O, bool extend=false)
@@ -570,27 +570,27 @@ void xaxis3At(picture pic=currentpicture, Label L="", axis axis,
void bounds() {
if(type == Min)
- y=pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin.y;
+ y=pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y;
else if(type == Max)
- y=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax.y;
+ y=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y;
else if(type == Both) {
- y2=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax.y;
+ y2=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y;
y=opposite ? y2 :
- (pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin.y);
+ (pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y);
}
if(type2 == Min)
- z=pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin.z;
+ z=pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z;
else if(type2 == Max)
- z=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax.z;
+ z=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z;
else if(type2 == Both) {
- z2=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax.z;
+ z2=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z;
z=opposite2 ? z2 :
- (pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin.z);
+ (pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z);
}
- real Xmin=finite(xmin) ? xmin : pic.userMin.x;
- real Xmax=finite(xmax) ? xmax : pic.userMax.x;
+ real Xmin=finite(xmin) ? xmin : pic.userMin().x;
+ real Xmax=finite(xmax) ? xmax : pic.userMax().x;
triple a=(Xmin,y,z);
triple b=(Xmax,y,z);
@@ -692,27 +692,27 @@ void yaxis3At(picture pic=currentpicture, Label L="", axis axis,
void bounds() {
if(type == Min)
- x=pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin.x;
+ x=pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x;
else if(type == Max)
- x=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax.x;
+ x=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x;
else if(type == Both) {
- x2=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax.x;
+ x2=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x;
x=opposite ? x2 :
- (pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin.x);
+ (pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x);
}
if(type2 == Min)
- z=pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin.z;
+ z=pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z;
else if(type2 == Max)
- z=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax.z;
+ z=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z;
else if(type2 == Both) {
- z2=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax.z;
+ z2=pic.scale.z.automax() ? tickMax3(pic).z : pic.userMax().z;
z=opposite2 ? z2 :
- (pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin.z);
+ (pic.scale.z.automin() ? tickMin3(pic).z : pic.userMin().z);
}
- real Ymin=finite(ymin) ? ymin : pic.userMin.y;
- real Ymax=finite(ymax) ? ymax : pic.userMax.y;
+ real Ymin=finite(ymin) ? ymin : pic.userMin().y;
+ real Ymax=finite(ymax) ? ymax : pic.userMax().y;
triple a=(x,Ymin,z);
triple b=(x,Ymax,z);
@@ -814,27 +814,27 @@ void zaxis3At(picture pic=currentpicture, Label L="", axis axis,
void bounds() {
if(type == Min)
- x=pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin.x;
+ x=pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x;
else if(type == Max)
- x=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax.x;
+ x=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x;
else if(type == Both) {
- x2=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax.x;
+ x2=pic.scale.x.automax() ? tickMax3(pic).x : pic.userMax().x;
x=opposite ? x2 :
- (pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin.x);
+ (pic.scale.x.automin() ? tickMin3(pic).x : pic.userMin().x);
}
if(type2 == Min)
- y=pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin.y;
+ y=pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y;
else if(type2 == Max)
- y=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax.y;
+ y=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y;
else if(type2 == Both) {
- y2=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax.y;
+ y2=pic.scale.y.automax() ? tickMax3(pic).y : pic.userMax().y;
y=opposite2 ? y2 :
- (pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin.y);
+ (pic.scale.y.automin() ? tickMin3(pic).y : pic.userMin().y);
}
- real Zmin=finite(zmin) ? zmin : pic.userMin.z;
- real Zmax=finite(zmax) ? zmax : pic.userMax.z;
+ real Zmin=finite(zmin) ? zmin : pic.userMin().z;
+ real Zmax=finite(zmax) ? zmax : pic.userMax().z;
triple a=(x,y,Zmin);
triple b=(x,y,Zmax);
@@ -893,14 +893,14 @@ void autoscale3(picture pic=currentpicture, axis axis)
if(!set) {
bounds mz;
- if(pic.userSetz) {
- mz=autoscale(pic.userMin.z,pic.userMax.z,pic.scale.z.scale);
+ if(pic.userSetz()) {
+ mz=autoscale(pic.userMin().z,pic.userMax().z,pic.scale.z.scale);
if(pic.scale.z.scale.logarithmic &&
- floor(pic.userMin.z) == floor(pic.userMax.z)) {
+ floor(pic.userMin().z) == floor(pic.userMax().z)) {
if(pic.scale.z.automin())
- pic.userMinz(floor(pic.userMin.z));
+ pic.userMinz(floor(pic.userMin().z));
if(pic.scale.z.automax())
- pic.userMaxz(ceil(pic.userMax.z));
+ pic.userMaxz(ceil(pic.userMax().z));
}
} else {mz.min=mz.max=0; pic.scale.set=false;}
@@ -938,9 +938,9 @@ void xaxis3(picture pic=currentpicture, Label L="", axis axis=YZZero,
newticks=true;
}
- if(newticks && pic.userSetx && ticks != NoTicks3) {
- if(xmin == -infinity) xmin=pic.userMin.x;
- if(xmax == infinity) xmax=pic.userMax.x;
+ if(newticks && pic.userSetx() && ticks != NoTicks3) {
+ if(xmin == -infinity) xmin=pic.userMin().x;
+ if(xmax == infinity) xmax=pic.userMax().x;
bounds mx=autoscale(xmin,xmax,pic.scale.x.scale);
pic.scale.x.tickMin=mx.min;
pic.scale.x.tickMax=mx.max;
@@ -952,15 +952,15 @@ void xaxis3(picture pic=currentpicture, Label L="", axis axis=YZZero,
if(xmin == -infinity && !axis.extend) {
if(pic.scale.set)
xmin=pic.scale.x.automin() ? pic.scale.x.tickMin :
- max(pic.scale.x.tickMin,pic.userMin.x);
- else xmin=pic.userMin.x;
+ max(pic.scale.x.tickMin,pic.userMin().x);
+ else xmin=pic.userMin().x;
}
if(xmax == infinity && !axis.extend) {
if(pic.scale.set)
xmax=pic.scale.x.automax() ? pic.scale.x.tickMax :
- min(pic.scale.x.tickMax,pic.userMax.x);
- else xmax=pic.userMax.x;
+ min(pic.scale.x.tickMax,pic.userMax().x);
+ else xmax=pic.userMax().x;
}
if(L.defaultposition) {
@@ -971,7 +971,7 @@ void xaxis3(picture pic=currentpicture, Label L="", axis axis=YZZero,
bool back=false;
if(axis.type == Both) {
triple v=currentprojection.normal;
- back=dot((0,pic.userMax.y-pic.userMin.y,0),v)*sgn(v.z) > 0;
+ back=dot((0,pic.userMax().y-pic.userMin().y,0),v)*sgn(v.z) > 0;
}
xaxis3At(pic,L,axis,xmin,xmax,p,ticks,arrow,margin,above,false,false,!back);
@@ -1012,9 +1012,9 @@ void yaxis3(picture pic=currentpicture, Label L="", axis axis=XZZero,
newticks=true;
}
- if(newticks && pic.userSety && ticks != NoTicks3) {
- if(ymin == -infinity) ymin=pic.userMin.y;
- if(ymax == infinity) ymax=pic.userMax.y;
+ if(newticks && pic.userSety() && ticks != NoTicks3) {
+ if(ymin == -infinity) ymin=pic.userMin().y;
+ if(ymax == infinity) ymax=pic.userMax().y;
bounds my=autoscale(ymin,ymax,pic.scale.y.scale);
pic.scale.y.tickMin=my.min;
pic.scale.y.tickMax=my.max;
@@ -1026,16 +1026,16 @@ void yaxis3(picture pic=currentpicture, Label L="", axis axis=XZZero,
if(ymin == -infinity && !axis.extend) {
if(pic.scale.set)
ymin=pic.scale.y.automin() ? pic.scale.y.tickMin :
- max(pic.scale.y.tickMin,pic.userMin.y);
- else ymin=pic.userMin.y;
+ max(pic.scale.y.tickMin,pic.userMin().y);
+ else ymin=pic.userMin().y;
}
if(ymax == infinity && !axis.extend) {
if(pic.scale.set)
ymax=pic.scale.y.automax() ? pic.scale.y.tickMax :
- min(pic.scale.y.tickMax,pic.userMax.y);
- else ymax=pic.userMax.y;
+ min(pic.scale.y.tickMax,pic.userMax().y);
+ else ymax=pic.userMax().y;
}
if(L.defaultposition) {
@@ -1046,7 +1046,7 @@ void yaxis3(picture pic=currentpicture, Label L="", axis axis=XZZero,
bool back=false;
if(axis.type == Both) {
triple v=currentprojection.normal;
- back=dot((pic.userMax.x-pic.userMin.x,0,0),v)*sgn(v.z) > 0;
+ back=dot((pic.userMax().x-pic.userMin().x,0,0),v)*sgn(v.z) > 0;
}
yaxis3At(pic,L,axis,ymin,ymax,p,ticks,arrow,margin,above,false,false,!back);
@@ -1087,9 +1087,9 @@ void zaxis3(picture pic=currentpicture, Label L="", axis axis=XYZero,
newticks=true;
}
- if(newticks && pic.userSetz && ticks != NoTicks3) {
- if(zmin == -infinity) zmin=pic.userMin.z;
- if(zmax == infinity) zmax=pic.userMax.z;
+ if(newticks && pic.userSetz() && ticks != NoTicks3) {
+ if(zmin == -infinity) zmin=pic.userMin().z;
+ if(zmax == infinity) zmax=pic.userMax().z;
bounds mz=autoscale(zmin,zmax,pic.scale.z.scale);
pic.scale.z.tickMin=mz.min;
pic.scale.z.tickMax=mz.max;
@@ -1101,15 +1101,15 @@ void zaxis3(picture pic=currentpicture, Label L="", axis axis=XYZero,
if(zmin == -infinity && !axis.extend) {
if(pic.scale.set)
zmin=pic.scale.z.automin() ? pic.scale.z.tickMin :
- max(pic.scale.z.tickMin,pic.userMin.z);
- else zmin=pic.userMin.z;
+ max(pic.scale.z.tickMin,pic.userMin().z);
+ else zmin=pic.userMin().z;
}
if(zmax == infinity && !axis.extend) {
if(pic.scale.set)
zmax=pic.scale.z.automax() ? pic.scale.z.tickMax :
- min(pic.scale.z.tickMax,pic.userMax.z);
- else zmax=pic.userMax.z;
+ min(pic.scale.z.tickMax,pic.userMax().z);
+ else zmax=pic.userMax().z;
}
if(L.defaultposition) {
@@ -1120,7 +1120,7 @@ void zaxis3(picture pic=currentpicture, Label L="", axis axis=XYZero,
bool back=false;
if(axis.type == Both) {
triple v=currentprojection.vector();
- back=dot((pic.userMax.x-pic.userMin.x,0,0),v)*sgn(v.y) > 0;
+ back=dot((pic.userMax().x-pic.userMin().x,0,0),v)*sgn(v.y) > 0;
}
zaxis3At(pic,L,axis,zmin,zmax,p,ticks,arrow,margin,above,false,false,!back);
@@ -1144,15 +1144,15 @@ void zlimits(picture pic=currentpicture, real min=-infinity, real max=infinity,
bounds mz;
if(pic.scale.z.automin() || pic.scale.z.automax())
- mz=autoscale(pic.userMin.z,pic.userMax.z,pic.scale.z.scale);
+ mz=autoscale(pic.userMin().z,pic.userMax().z,pic.scale.z.scale);
if(pic.scale.z.automin) {
if(pic.scale.z.automin()) pic.userMinz(mz.min);
- } else pic.userMinz(pic.scale.z.T(min));
+ } else pic.userMinz(min(pic.scale.z.T(min),pic.scale.z.T(max)));
if(pic.scale.z.automax) {
if(pic.scale.z.automax()) pic.userMaxz(mz.max);
- } else pic.userMaxz(pic.scale.z.T(max));
+ } else pic.userMaxz(max(pic.scale.z.T(min),pic.scale.z.T(max)));
}
// Restrict the x, y, and z limits to box(min,max).
diff --git a/Build/source/utils/asymptote/base/grid3.asy b/Build/source/utils/asymptote/base/grid3.asy
index afd621eb741..98e043a71d7 100644
--- a/Build/source/utils/asymptote/base/grid3.asy
+++ b/Build/source/utils/asymptote/base/grid3.asy
@@ -33,18 +33,20 @@ struct grid3 {
typedef grid3 grid3routine(picture pic);
-triple X(picture pic) {return (pic.userMax.x,pic.userMin.y,pic.userMin.z);}
-triple XY(picture pic) {return (pic.userMax.x,pic.userMax.y,pic.userMin.z);}
-triple Y(picture pic) {return (pic.userMin.x,pic.userMax.y,pic.userMin.z);}
-triple YZ(picture pic) {return (pic.userMin.x,pic.userMax.y,pic.userMax.z);}
-triple Z(picture pic) {return (pic.userMin.x,pic.userMin.y,pic.userMax.z);}
-triple ZX(picture pic) {return (pic.userMax.x,pic.userMin.y,pic.userMax.z);}
+triple X(picture pic) {return (pic.userMax().x,pic.userMin().y,pic.userMin().z);}
+triple XY(picture pic) {return (pic.userMax().x,pic.userMax().y,pic.userMin().z);}
+triple Y(picture pic) {return (pic.userMin().x,pic.userMax().y,pic.userMin().z);}
+triple YZ(picture pic) {return (pic.userMin().x,pic.userMax().y,pic.userMax().z);}
+triple Z(picture pic) {return (pic.userMin().x,pic.userMin().y,pic.userMax().z);}
+triple ZX(picture pic) {return (pic.userMax().x,pic.userMin().y,pic.userMax().z);}
grid3routine XYgrid(position pos=Relative(0)) {
return new grid3(picture pic) {
grid3 og;
- og.create(pic,pic.userMin--X(pic),Y(pic)--XY(pic),pic.userMin--Z(pic),
- pic.userMin.x,pic.userMax.x,pos,pic.scale.x);
+ triple m=pic.userMin();
+ triple M=pic.userMax();
+ og.create(pic,m--X(pic),Y(pic)--XY(pic),m--Z(pic),
+ m.x,M.x,pos,pic.scale.x);
return og;
};
};
@@ -53,8 +55,10 @@ grid3routine XYgrid=XYgrid();
grid3routine YXgrid(position pos=Relative(0)) {
return new grid3(picture pic) {
grid3 og;
- og.create(pic,pic.userMin--Y(pic),X(pic)--XY(pic),pic.userMin--Z(pic),
- pic.userMin.y,pic.userMax.y,pos,pic.scale.y);
+ triple m=pic.userMin();
+ triple M=pic.userMax();
+ og.create(pic,m--Y(pic),X(pic)--XY(pic),m--Z(pic),
+ m.y,M.y,pos,pic.scale.y);
return og;
};
};
@@ -64,8 +68,10 @@ grid3routine YXgrid=YXgrid();
grid3routine XZgrid(position pos=Relative(0)) {
return new grid3(picture pic) {
grid3 og;
- og.create(pic,pic.userMin--X(pic),Z(pic)--ZX(pic),pic.userMin--Y(pic),
- pic.userMin.x,pic.userMax.x,pos,pic.scale.x);
+ triple m=pic.userMin();
+ triple M=pic.userMax();
+ og.create(pic,m--X(pic),Z(pic)--ZX(pic),m--Y(pic),
+ m.x,M.x,pos,pic.scale.x);
return og;
};
};
@@ -74,8 +80,10 @@ grid3routine XZgrid=XZgrid();
grid3routine ZXgrid(position pos=Relative(0)) {
return new grid3(picture pic) {
grid3 og;
- og.create(pic,pic.userMin--Z(pic),X(pic)--ZX(pic),pic.userMin--Y(pic),
- pic.userMin.z,pic.userMax.z,pos,pic.scale.z);
+ triple m=pic.userMin();
+ triple M=pic.userMax();
+ og.create(pic,m--Z(pic),X(pic)--ZX(pic),m--Y(pic),
+ m.z,M.z,pos,pic.scale.z);
return og;
};
};
@@ -84,8 +92,10 @@ grid3routine ZXgrid=ZXgrid();
grid3routine YZgrid(position pos=Relative(0)) {
return new grid3(picture pic) {
grid3 og;
- og.create(pic,pic.userMin--Y(pic),Z(pic)--YZ(pic),pic.userMin--X(pic),
- pic.userMin.y,pic.userMax.y,pos,pic.scale.y);
+ triple m=pic.userMin();
+ triple M=pic.userMax();
+ og.create(pic,m--Y(pic),Z(pic)--YZ(pic),m--X(pic),
+ m.y,M.y,pos,pic.scale.y);
return og;
};
};
@@ -94,8 +104,10 @@ grid3routine YZgrid=YZgrid();
grid3routine ZYgrid(position pos=Relative(0)) {
return new grid3(picture pic) {
grid3 og;
- og.create(pic,pic.userMin--Z(pic),Y(pic)--YZ(pic),pic.userMin--X(pic),
- pic.userMin.z,pic.userMax.z,pos,pic.scale.z);
+ triple m=pic.userMin();
+ triple M=pic.userMax();
+ og.create(pic,m--Z(pic),Y(pic)--YZ(pic),m--X(pic),
+ m.z,M.z,pos,pic.scale.z);
return og;
};
};
diff --git a/Build/source/utils/asymptote/base/math.asy b/Build/source/utils/asymptote/base/math.asy
index 0dfddff7f2f..77c0664895f 100644
--- a/Build/source/utils/asymptote/base/math.asy
+++ b/Build/source/utils/asymptote/base/math.asy
@@ -113,6 +113,30 @@ real[] partialsum(real[] a, real[] dx)
return b;
}
+// Given an integer array a, return its partial sums.
+int[] partialsum(int[] a)
+{
+ int[] b=new int[a.length];
+ int sum=0;
+ for(int i=0; i < a.length; ++i) {
+ sum += a[i];
+ b[i]=sum;
+ }
+ return b;
+}
+
+// Given an integer array a, return its partial dx-weighted sums.
+int[] partialsum(int[] a, int[] dx)
+{
+ int[] b=new int[a.length];
+ int sum=0;
+ for(int i=0; i < a.length; ++i) {
+ sum += a[i]*dx[i];
+ b[i]=sum;
+ }
+ return b;
+}
+
// If strict=false, return whether i > j implies a[i] >= a[j]
// If strict=true, return whether i > j implies a[i] > a[j]
bool increasing(real[] a, bool strict=false)
@@ -232,11 +256,12 @@ bool rectangular(triple[][] m)
// size of picture pic.
void drawline(picture pic=currentpicture, pair P, pair Q, pen p=currentpen)
{
- pic.add(new void (frame f, transform t, transform, pair m, pair M) {
+ pic.add(new void (frame f, transform t, transform T, pair m, pair M) {
// Reduce the bounds by the size of the pen.
m -= min(p); M -= max(p);
// Calculate the points and direction vector in the transformed space.
+ t=t*T;
pair z=t*P;
pair v=t*Q-z;
diff --git a/Build/source/utils/asymptote/base/palette.asy b/Build/source/utils/asymptote/base/palette.asy
index 41a40a04a85..88f8ae2c42f 100644
--- a/Build/source/utils/asymptote/base/palette.asy
+++ b/Build/source/utils/asymptote/base/palette.asy
@@ -138,6 +138,18 @@ void image(picture pic=currentpicture, pen[][] data, pair initial, pair final,
pic.addBox(initial,final);
}
+void image(picture pic=currentpicture, pen f(int, int), int width, int height,
+ pair initial, pair final, bool antialias=false)
+{
+ initial=Scale(pic,initial);
+ final=Scale(pic,final);
+
+ pic.add(new void(frame F, transform t) {
+ _image(F,f,width,height,initial,final,t,antialias=antialias);
+ },true);
+ pic.addBox(initial,final);
+}
+
bounds image(picture pic=currentpicture, pair[] z, real[] f,
range range=Full, pen[] palette)
{
diff --git a/Build/source/utils/asymptote/base/plain_arrows.asy b/Build/source/utils/asymptote/base/plain_arrows.asy
index 490f76f777c..59b65aa4126 100644
--- a/Build/source/utils/asymptote/base/plain_arrows.asy
+++ b/Build/source/utils/asymptote/base/plain_arrows.asy
@@ -469,30 +469,87 @@ void draw(frame f, path g, pen p=currentpen, arrowbar arrow)
add(f,pic.fit());
}
-void draw(picture pic=currentpicture, Label L="", path g, align align=NoAlign,
- pen p=currentpen, arrowbar arrow=None, arrowbar bar=None,
- margin margin=NoMargin, Label legend="", marker marker=nomarker)
-{
- Label L=L.copy();
- L.align(align);
- if(marker != nomarker && !marker.above) marker.mark(pic,g);
- bool drawpath=arrow(pic,g,p,margin);
- if(bar(pic,g,p,margin) && drawpath) _draw(pic,g,p,margin);
- if(L.s != "") {
- L.p(p);
- L.out(pic,g);
+void draw(picture pic=currentpicture, Label L=null, path g,
+ align align=NoAlign, pen p=currentpen, arrowbar arrow=None,
+ arrowbar bar=None, margin margin=NoMargin, Label legend=null,
+ marker marker=nomarker)
+{
+ // These if statements are ordered in such a way that the most common case
+ // (with just a path and a pen) executes the least bytecode.
+ if (marker == nomarker)
+ {
+ if (arrow == None && bar == None)
+ {
+ if (margin == NoMargin && size(nib(p)) == 0)
+ {
+ pic.addExactAbove(
+ new void(frame f, transform t, transform T, pair, pair) {
+ _draw(f,t*T*g,p);
+ });
+ pic.addPath(g,p);
+
+ // Jumping over else clauses takes time, so test if we can return
+ // here.
+ if (L == null && legend == null)
+ return;
+ }
+ else // With margin or polygonal pen.
+ {
+ _draw(pic, g, p, margin);
+ }
+ }
+ else /* arrow or bar */
+ {
+ // Note we are using & instead of && as both arrow and bar need to be
+ // called.
+ if (arrow(pic, g, p, margin) & bar(pic, g, p, margin))
+ _draw(pic, g, p, margin);
+ }
+
+ if(L != null && L.s != "") {
+ L=L.copy();
+ L.align(align);
+ L.p(p);
+ L.out(pic,g);
+ }
+
+ if(legend != null && legend.s != "") {
+ legend.p(p);
+ pic.legend.push(Legend(legend.s,legend.p,p,marker.f,marker.above));
+ }
}
- if(legend.s != "") {
- legend.p(p);
- pic.legend.push(Legend(legend.s,legend.p,p,marker.f,marker.above));
+ else /* marker != nomarker */
+ {
+ if(marker != nomarker && !marker.above) marker.mark(pic,g);
+
+ // Note we are using & instead of && as both arrow and bar need to be
+ // called.
+ if ((arrow == None || arrow(pic, g, p, margin)) &
+ (bar == None || bar(pic, g, p, margin)))
+ {
+ _draw(pic, g, p, margin);
+ }
+
+ if(L != null && L.s != "") {
+ L=L.copy();
+ L.align(align);
+ L.p(p);
+ L.out(pic,g);
+ }
+
+ if(legend != null && legend.s != "") {
+ legend.p(p);
+ pic.legend.push(Legend(legend.s,legend.p,p,marker.f,marker.above));
+ }
+
+ if(marker != nomarker && marker.above) marker.mark(pic,g);
}
- if(marker != nomarker && marker.above) marker.mark(pic,g);
}
// Draw a fixed-size line about the user-coordinate 'origin'.
-void draw(pair origin, picture pic=currentpicture, Label L="", path g,
+void draw(pair origin, picture pic=currentpicture, Label L=null, path g,
align align=NoAlign, pen p=currentpen, arrowbar arrow=None,
- arrowbar bar=None, margin margin=NoMargin, Label legend="",
+ arrowbar bar=None, margin margin=NoMargin, Label legend=null,
marker marker=nomarker)
{
picture opic;
@@ -501,21 +558,22 @@ void draw(pair origin, picture pic=currentpicture, Label L="", path g,
}
void draw(picture pic=currentpicture, explicit path[] g, pen p=currentpen,
- Label legend="", marker marker=nomarker)
+ Label legend=null, marker marker=nomarker)
{
+ // This could be optimized to size and draw the entire array as a batch.
for(int i=0; i < g.length-1; ++i)
draw(pic,g[i],p,marker);
if(g.length > 0) draw(pic,g[g.length-1],p,legend,marker);
}
void draw(picture pic=currentpicture, guide[] g, pen p=currentpen,
- Label legend="", marker marker=nomarker)
+ Label legend=null, marker marker=nomarker)
{
draw(pic,(path[]) g,p,legend,marker);
}
void draw(pair origin, picture pic=currentpicture, explicit path[] g,
- pen p=currentpen, Label legend="", marker marker=nomarker)
+ pen p=currentpen, Label legend=null, marker marker=nomarker)
{
picture opic;
draw(opic,g,p,legend,marker);
@@ -523,21 +581,23 @@ void draw(pair origin, picture pic=currentpicture, explicit path[] g,
}
void draw(pair origin, picture pic=currentpicture, guide[] g, pen p=currentpen,
- Label legend="", marker marker=nomarker)
+ Label legend=null, marker marker=nomarker)
{
draw(origin,pic,(path[]) g,p,legend,marker);
}
// Align an arrow pointing to b from the direction dir. The arrow is
// 'length' PostScript units long.
-void arrow(picture pic=currentpicture, Label L="", pair b, pair dir,
+void arrow(picture pic=currentpicture, Label L=null, pair b, pair dir,
real length=arrowlength, align align=NoAlign,
pen p=currentpen, arrowbar arrow=Arrow, margin margin=EndMargin)
{
- Label L=L.copy();
- if(L.defaultposition) L.position(0);
- L.align(L.align,dir);
- L.p(p);
+ if(L != null && L.s != "") {
+ L=L.copy();
+ if(L.defaultposition) L.position(0);
+ L.align(L.align,dir);
+ L.p(p);
+ }
marginT margin=margin(b--b,p); // Extract margin.begin and margin.end
pair a=(margin.begin+length+margin.end)*unit(dir);
draw(b,pic,L,a--(0,0),align,p,arrow,margin);
@@ -562,6 +622,7 @@ frame[] fit2(picture[] pictures, picture all)
}
// Fit an array of pictures simultaneously using the size of the first picture.
+// TODO: Remove unused arguments.
frame[] fit(string prefix="", picture[] pictures, string format="",
bool view=true, string options="", string script="",
projection P=currentprojection)
diff --git a/Build/source/utils/asymptote/base/plain_bounds.asy b/Build/source/utils/asymptote/base/plain_bounds.asy
new file mode 100644
index 00000000000..71c304da02f
--- /dev/null
+++ b/Build/source/utils/asymptote/base/plain_bounds.asy
@@ -0,0 +1,783 @@
+include plain_scaling;
+
+// After an transformation, produce new coordinate bounds. For paths that
+// have been added, this is only an approximation since it takes the bounds of
+// their transformed bounding box.
+private void addTransformedCoords(coords2 dest, transform t,
+ coords2 point, coords2 min, coords2 max)
+{
+ dest.push(t, point, point);
+
+ // Add in all 4 corner coords, to properly size rectangular pictures.
+ dest.push(t,min,min);
+ dest.push(t,min,max);
+ dest.push(t,max,min);
+ dest.push(t,max,max);
+}
+
+// Adds another sizing restriction to the coordinates, but only if it is
+// maximal, that is, if under some scaling, this coordinate could be the
+// largest.
+private void addIfMaximal(coord[] coords, real user, real truesize) {
+ // TODO: Test promoting coordinates for efficiency.
+
+ for (coord c : coords)
+ if (user <= c.user && truesize <= c.truesize)
+ // Not maximal.
+ return;
+
+ // The coordinate is not dominated by any existing extreme, so it is
+ // maximal and will be added, but first remove any coords it now dominates.
+ int i = 0;
+ while (i < coords.length) {
+ coord c = coords[i];
+ if (c.user <= user && c.truesize <= truesize)
+ coords.delete(i);
+ else
+ ++i;
+ }
+
+ // Add the coordinate to the extremes.
+ coords.push(coord.build(user, truesize));
+}
+
+private void addIfMaximal(coord[] dest, coord[] src)
+{
+ // This may be inefficient, as it rebuilds the coord struct when adding it.
+ for (coord c : src)
+ addIfMaximal(dest, c.user, c.truesize);
+}
+
+// Same as addIfMaximal, but testing for minimal coords.
+private void addIfMinimal(coord[] coords, real user, real truesize) {
+ for (coord c : coords)
+ if (user >= c.user && truesize >= c.truesize)
+ return;
+
+ int i = 0;
+ while (i < coords.length) {
+ coord c = coords[i];
+ if (c.user >= user && c.truesize >= truesize)
+ coords.delete(i);
+ else
+ ++i;
+ }
+
+ coords.push(coord.build(user, truesize));
+}
+
+private void addIfMinimal(coord[] dest, coord[] src)
+{
+ for (coord c : src)
+ addIfMinimal(dest, c.user, c.truesize);
+}
+
+// This stores a list of sizing bounds for picture data. If the object is
+// frozen, then it cannot be modified further, and therefore can be safely
+// passed by reference and stored in the sizing data for multiple pictures.
+private struct freezableBounds {
+ restricted bool frozen = false;
+ void freeze() {
+ frozen = true;
+ }
+
+ // Optional links to further (frozen) sizing data.
+ private freezableBounds[] links;
+
+ // Links to (frozen) sizing data that is transformed when added here.
+ private static struct transformedBounds {
+ transform t;
+ freezableBounds link;
+ };
+ private transformedBounds[] tlinks;
+
+ // The sizing data. It cannot be modified once this object is frozen.
+ private coords2 point, min, max;
+
+ // A bound represented by a path. Using the path instead of the bounding
+ // box means it will be accurate after a transformation by coordinates.
+ private path[] pathBounds;
+
+ // A bound represented by a path and a pen.
+ // As often many paths use the same pen, we store an array of paths.
+ private static struct pathpen {
+ path[] g; pen p;
+
+ void operator init(path g, pen p) {
+ this.g.push(g);
+ this.p = p;
+ }
+ }
+ private static pathpen operator *(transform t, pathpen pp) {
+ // Should the pen be transformed?
+ pathpen newpp;
+ for (path g : pp.g)
+ newpp.g.push(t*g);
+ newpp.p = pp.p;
+ return newpp;
+ }
+
+ // WARNING: Due to crazy optimizations, if this array is changed between an
+ // empty and non-empty state, the assignment of a method to
+ // addPath(path,pen) must also change.
+ private pathpen[] pathpenBounds;
+
+ // Once frozen, the sizing is immutable, and therefore we can compute and
+ // store the extremal coordinates.
+ public static struct extremes {
+ coord[] left, bottom, right, top;
+
+ void operator init(coord[] left, coord[] bottom,
+ coord[] right, coord[] top) {
+ this.left = left;
+ this.bottom = bottom;
+ this.right = right;
+ this.top = top;
+ }
+
+ }
+ private static void addMaxToExtremes(extremes e, pair user, pair truesize) {
+ addIfMaximal(e.right, user.x, truesize.x);
+ addIfMaximal(e.top, user.y, truesize.y);
+ }
+ private static void addMinToExtremes(extremes e, pair user, pair truesize) {
+ addIfMinimal(e.left, user.x, truesize.x);
+ addIfMinimal(e.bottom, user.y, truesize.y);
+ }
+ private static void addMaxToExtremes(extremes e, coords2 coords) {
+ addIfMaximal(e.right, coords.x);
+ addIfMaximal(e.top, coords.y);
+ }
+ private static void addMinToExtremes(extremes e, coords2 coords) {
+ addIfMinimal(e.left, coords.x);
+ addIfMinimal(e.bottom, coords.y);
+ }
+
+ private extremes cachedExtremes = null;
+
+ // Once frozen, getMutable returns a new object based on this one, which can
+ // be modified.
+ freezableBounds getMutable() {
+ assert(frozen);
+ var f = new freezableBounds;
+ f.links.push(this);
+ return f;
+ }
+
+ freezableBounds transformed(transform t) {
+ // Freeze these bounds, as we are storing a reference to them.
+ freeze();
+
+ var tlink = new transformedBounds;
+ tlink.t = t;
+ tlink.link = this;
+
+ var b = new freezableBounds;
+ b.tlinks.push(tlink);
+
+ return b;
+ }
+
+ void append(freezableBounds b) {
+ // Check that we can modify the object.
+ assert(!frozen);
+
+ //TODO: If b is "small", ie. a single tlink or cliplink, just copy the
+ //link.
+
+ // As we only reference b, we must freeze it to ensure it does not change.
+ b.freeze();
+ links.push(b);
+ }
+
+ void addPoint(pair user, pair truesize) {
+ assert(!frozen);
+ point.push(user, truesize);
+ }
+
+ void addBox(pair userMin, pair userMax, pair trueMin, pair trueMax) {
+ assert(!frozen);
+ this.min.push(userMin, trueMin);
+ this.max.push(userMax, trueMax);
+ }
+
+ void addPath(path g) {
+ // This, and other asserts have been removed to speed things up slightly.
+ //assert(!frozen);
+ this.pathBounds.push(g);
+ }
+
+ void addPath(path[] g) {
+ //assert(!frozen);
+ this.pathBounds.append(g);
+ }
+
+ // To squeeze out a bit more performance, this method is either assigned
+ // addPathToNonEmptyArray or addPathToEmptyArray depending on the state of
+ // the pathpenBounds array.
+ void addPath(path g, pen p);
+
+ private void addPathToNonEmptyArray(path g, pen p) {
+ //assert(!frozen);
+ //assert(!pathpenBounds.empty());
+ var pp = pathpenBounds[0];
+
+ // Test if the pens are equal or have the same bounds.
+ if (pp.p == p || (min(pp.p) == min(p) && max(pp.p) == max(p))) {
+ // If this path has the same pen as the last one, just add it to the
+ // array corresponding to that pen.
+ pp.g.push(g);
+ }
+ else {
+ // A different pen. Start a new bound and put it on the front. Put
+ // the old bound at the end of the array.
+ pathpenBounds[0] = pathpen(g,p);
+ pathpenBounds.push(pp);
+ }
+ }
+ void addPathToEmptyArray(path g, pen p) {
+ //assert(!frozen);
+ //assert(pathpenBounds.empty());
+
+ pathpenBounds.push(pathpen(g,p));
+ addPath = addPathToNonEmptyArray;
+ }
+
+ // Initial setting for addPath.
+ addPath = addPathToEmptyArray;
+
+ // Transform the sizing info by t then add the result to the coords
+ // structure.
+ private void accumulateCoords(transform t, coords2 coords) {
+ for (var link : links)
+ link.accumulateCoords(t, coords);
+
+ for (var tlink : tlinks)
+ tlink.link.accumulateCoords(t*tlink.t, coords);
+
+ addTransformedCoords(coords, t, this.point, this.min, this.max);
+
+ for (var g : pathBounds) {
+ g = t*g;
+ coords.push(min(g), (0,0));
+ coords.push(max(g), (0,0));
+ }
+
+ for (var pp: pathpenBounds) {
+ pair pm = min(pp.p), pM = max(pp.p);
+ for (var g : pp.g) {
+ g = t*g;
+ coords.push(min(g), pm);
+ coords.push(max(g), pM);
+ }
+ }
+ }
+
+ // Add all of the sizing info to the given coords structure.
+ private void accumulateCoords(coords2 coords) {
+ for (var link : links)
+ link.accumulateCoords(coords);
+
+ for (var tlink : tlinks)
+ tlink.link.accumulateCoords(tlink.t, coords);
+
+ coords.append(this.point);
+ coords.append(this.min);
+ coords.append(this.max);
+
+ for (var g : pathBounds) {
+ coords.push(min(g), (0,0));
+ coords.push(max(g), (0,0));
+ }
+
+ for (var pp: pathpenBounds) {
+ pair pm = min(pp.p), pM = max(pp.p);
+ for (var g : pp.g) {
+ coords.push(min(g), pm);
+ coords.push(max(g), pM);
+ }
+ }
+ }
+
+ // Returns all of the coords that this sizing data represents.
+ private coords2 allCoords() {
+ coords2 coords;
+ accumulateCoords(coords);
+ return coords;
+ }
+
+ private void addLocalsToExtremes(transform t, extremes e) {
+ coords2 coords;
+ addTransformedCoords(coords, t, this.point, this.min, this.max);
+ addMinToExtremes(e, coords);
+ addMaxToExtremes(e, coords);
+
+ if (pathBounds.length > 0) {
+ addMinToExtremes(e, minAfterTransform(t, pathBounds), (0,0));
+ addMaxToExtremes(e, maxAfterTransform(t, pathBounds), (0,0));
+ }
+
+ for (var pp : pathpenBounds) {
+ if (pp.g.length > 0) {
+ addMinToExtremes(e, minAfterTransform(t, pp.g), min(pp.p));
+ addMaxToExtremes(e, maxAfterTransform(t, pp.g), max(pp.p));
+ }
+ }
+ }
+
+ private void addToExtremes(transform t, extremes e) {
+ for (var link : links)
+ link.addToExtremes(t, e);
+
+ for (var tlink : tlinks)
+ tlink.link.addToExtremes(t*tlink.t, e);
+
+ addLocalsToExtremes(t, e);
+ }
+
+ private void addLocalsToExtremes(extremes e) {
+ addMinToExtremes(e, point);
+ addMaxToExtremes(e, point);
+ addMinToExtremes(e, min);
+ addMaxToExtremes(e, max);
+
+ if (pathBounds.length > 0) {
+ addMinToExtremes(e, min(pathBounds), (0,0));
+ addMaxToExtremes(e, max(pathBounds), (0,0));
+ }
+
+ for (var pp : pathpenBounds) {
+ if (pp.g.length > 0) {
+ addMinToExtremes(e, min(pp.g), min(pp.p));
+ addMaxToExtremes(e, max(pp.g), max(pp.p));
+ }
+ }
+ }
+
+ private void addToExtremes(extremes e) {
+ for (var link : links)
+ link.addToExtremes(e);
+
+ for (var tlink : tlinks)
+ tlink.link.addToExtremes(tlink.t, e);
+
+ addLocalsToExtremes(e);
+ }
+
+ private static void write(extremes e) {
+ static void write(coord[] coords) {
+ for (coord c : coords)
+ write(" " + (string)c.user + " u + " + (string)c.truesize);
+ }
+ write("left:");
+ write(e.left);
+ write("bottom:");
+ write(e.bottom);
+ write("right:");
+ write(e.right);
+ write("top:");
+ write(e.top);
+ }
+
+ // Returns the extremal coordinates of the sizing data.
+ public extremes extremes() {
+ if (cachedExtremes == null) {
+ freeze();
+
+ extremes e;
+ addToExtremes(e);
+ cachedExtremes = e;
+ }
+
+ return cachedExtremes;
+ }
+
+ // Helper functions for computing the usersize bounds. usermin and usermax
+ // would be easily computable from extremes, except that the picture
+ // interface actually allows calls that manually change the usermin and
+ // usermax values. Therefore, we have to compute these values separately.
+ private static struct bounds {
+ bool areSet=false;
+ pair min;
+ pair max;
+ }
+ private static struct boundsAccumulator {
+ pair[] mins;
+ pair[] maxs;
+
+ void push(pair m, pair M) {
+ mins.push(m);
+ maxs.push(M);
+ }
+
+ void push(bounds b) {
+ if (b.areSet)
+ push(b.min, b.max);
+ }
+
+ void push(transform t, bounds b) {
+ if (b.areSet) {
+ pair[] box = { t*(b.min.x,b.max.y), t*b.max,
+ t*b.min.x, t*(b.min.x,b.max.y) };
+ for (var z : box)
+ push(z,z);
+ }
+ }
+
+ void pushUserCoords(coords2 min, coords2 max) {
+ int n = min.x.length;
+ assert(min.y.length == n);
+ assert(max.x.length == n);
+ assert(max.y.length == n);
+
+ for (int i = 0; i < n; ++i)
+ push((min.x[i].user, min.y[i].user),
+ (max.x[i].user, max.y[i].user));
+ }
+
+ bounds collapse() {
+ bounds b;
+ if (mins.length > 0) {
+ b.areSet = true;
+ b.min = minbound(mins);
+ b.max = maxbound(maxs);
+ }
+ else {
+ b.areSet = false;
+ }
+ return b;
+ }
+ }
+
+ // The user bounds already calculated for this data.
+ private bounds storedUserBounds = null;
+
+ private void accumulateUserBounds(boundsAccumulator acc)
+ {
+ if (storedUserBounds != null) {
+ assert(frozen);
+ acc.push(storedUserBounds);
+ } else {
+ acc.pushUserCoords(point, point);
+ acc.pushUserCoords(min, max);
+ if (pathBounds.length > 0)
+ acc.push(min(pathBounds), max(pathBounds));
+ for (var pp : pathpenBounds)
+ acc.push(min(pp.g), max(pp.g));
+ for (var link : links)
+ link.accumulateUserBounds(acc);
+
+ // Transforms are handled as they were in the old system.
+ for (var tlink : tlinks) {
+ boundsAccumulator tacc;
+ tlink.link.accumulateUserBounds(tacc);
+ acc.push(tlink.t, tacc.collapse());
+ }
+ }
+ }
+
+ private void computeUserBounds() {
+ freeze();
+ boundsAccumulator acc;
+ accumulateUserBounds(acc);
+ storedUserBounds = acc.collapse();
+ }
+
+ private bounds userBounds() {
+ if (storedUserBounds == null)
+ computeUserBounds();
+
+ assert(storedUserBounds != null);
+ return storedUserBounds;
+ }
+
+ // userMin/userMax returns the minimal/maximal userspace coordinate of the
+ // sizing data. As coordinates for objects such as labels can have
+ // significant truesize dimensions, this userMin/userMax values may not
+ // correspond closely to the end of the screen, and are of limited use.
+ // userSetx and userSety determine if there is sizing data in order to even
+ // have userMin/userMax defined.
+ public bool userBoundsAreSet() {
+ return userBounds().areSet;
+ }
+
+ public pair userMin() {
+ return userBounds().min;
+ }
+ public pair userMax() {
+ return userBounds().max;
+ }
+
+ // To override the true userMin and userMax bounds, first compute the
+ // userBounds as they should be at this point, then change the values.
+ public void alterUserBound(string which, real val) {
+ // We are changing the bounds data, so it cannot be frozen yet. After the
+ // user bounds are set, however, the sizing data cannot change, so it will
+ // be frozen.
+ assert(!frozen);
+ computeUserBounds();
+ assert(frozen);
+
+ var b = storedUserBounds;
+ if (which == "minx")
+ b.min = (val, b.min.y);
+ else if (which == "miny")
+ b.min = (b.min.x, val);
+ else if (which == "maxx")
+ b.max = (val, b.max.y);
+ else {
+ assert(which == "maxy");
+ b.max = (b.max.x, val);
+ }
+ }
+
+ // A temporary measure. Stuffs all of the data from the links and paths
+ // into the coords.
+ private void flatten() {
+ assert(!frozen);
+
+ // First, compute the user bounds, taking into account any manual
+ // alterations.
+ computeUserBounds();
+
+ // Calculate all coordinates.
+ coords2 coords = allCoords();
+
+ // Erase all the old data.
+ point.erase();
+ min.erase();
+ max.erase();
+ pathBounds.delete();
+ pathpenBounds.delete();
+ addPath = addPathToEmptyArray;
+ links.delete();
+ tlinks.delete();
+
+ // Put all of the coordinates into point.
+ point = coords;
+ }
+
+ void xclip(real Min, real Max) {
+ assert(!frozen);
+ flatten();
+ point.xclip(Min,Max);
+ min.xclip(Min,Max);
+ max.xclip(Min,Max);
+
+ // Cap the userBounds.
+ bounds b = storedUserBounds;
+ b.min = (max(Min, b.min.x), b.min.y);
+ b.max = (min(Max, b.max.x), b.max.y);
+ }
+
+ void yclip(real Min, real Max) {
+ assert(!frozen);
+ flatten();
+ point.yclip(Min,Max);
+ min.yclip(Min,Max);
+ max.yclip(Min,Max);
+
+ // Cap the userBounds.
+ bounds b = storedUserBounds;
+ b.min = (b.min.x, max(Min, b.min.y));
+ b.max = (b.max.x, min(Max, b.max.y));
+ }
+
+ // Calculate the min for the final frame, given the coordinate transform.
+ pair min(transform t) {
+ extremes e = extremes();
+ if (e.left.length == 0)
+ return 0;
+
+ pair a=t*(1,1)-t*(0,0), b=t*(0,0);
+ scaling xs=scaling.build(a.x,b.x);
+ scaling ys=scaling.build(a.y,b.y);
+
+ return (min(infinity, xs, e.left), min(infinity, ys, e.bottom));
+ }
+
+ // Calculate the max for the final frame, given the coordinate transform.
+ pair max(transform t) {
+ extremes e = extremes();
+ if (e.right.length == 0)
+ return 0;
+
+ pair a=t*(1,1)-t*(0,0), b=t*(0,0);
+ scaling xs=scaling.build(a.x,b.x);
+ scaling ys=scaling.build(a.y,b.y);
+
+ return (max(-infinity, xs, e.right), max(-infinity, ys, e.top));
+ }
+
+ // Returns the transform for turning user-space pairs into true-space pairs.
+ transform scaling(real xsize, real ysize,
+ real xunitsize, real yunitsize,
+ bool keepAspect, bool warn) {
+ if(xsize == 0 && xunitsize == 0 && ysize == 0 && yunitsize == 0)
+ return identity();
+
+ // Get the extremal coordinates.
+ extremes e = extremes();
+
+ real sx;
+ if(xunitsize == 0) {
+ if(xsize != 0) sx=calculateScaling("x",e.left,e.right,xsize,warn);
+ } else sx=xunitsize;
+
+ /* Possible alternative code :
+ real sx = xunitsize != 0 ? xunitsize :
+ xsize != 0 ? calculateScaling("x", Coords.x, xsize, warn) :
+ 0; */
+
+ real sy;
+ if(yunitsize == 0) {
+ if(ysize != 0) sy=calculateScaling("y",e.bottom,e.top,ysize,warn);
+ } else sy=yunitsize;
+
+ if(sx == 0) {
+ sx=sy;
+ if(sx == 0)
+ return identity();
+ } else if(sy == 0) sy=sx;
+
+
+ if(keepAspect && (xunitsize == 0 || yunitsize == 0))
+ return scale(min(sx,sy));
+ else
+ return scale(sx,sy);
+ }
+}
+
+struct bounds {
+ private var base = new freezableBounds;
+
+ // We should probably put this back into picture.
+ bool exact = true;
+
+ // Called just before modifying the sizing data. It ensures base is
+ // non-frozen.
+ // Note that this is manually inlined for speed reasons in a couple often
+ // called methods below.
+ private void makeMutable() {
+ if (base.frozen)
+ base = base.getMutable();
+ //assert(!base.frozen); // Disabled for speed reasons.
+ }
+
+ void erase() {
+ // Just discard the old bounds.
+ base = new freezableBounds;
+
+ // We don't reset the 'exact' field, for backward compatibility.
+ }
+
+ bounds copy() {
+ // Freeze the underlying bounds and make a shallow copy.
+ base.freeze();
+
+ var b = new bounds;
+ b.base = this.base;
+ b.exact = this.exact;
+ return b;
+ }
+
+ bounds transformed(transform t) {
+ var b = new bounds;
+ b.base = base.transformed(t);
+ b.exact = this.exact;
+ return b;
+ }
+
+ void append(bounds b) {
+ makeMutable();
+ base.append(b.base);
+ }
+
+ void append(transform t, bounds b) {
+ // makeMutable will be called by append.
+ if (t == identity())
+ append(b);
+ else
+ append(b.transformed(t));
+ }
+
+ void addPoint(pair user, pair truesize) {
+ makeMutable();
+ base.addPoint(user, truesize);
+ }
+
+ void addBox(pair userMin, pair userMax, pair trueMin, pair trueMax) {
+ makeMutable();
+ base.addBox(userMin, userMax, trueMin, trueMax);
+ }
+
+ void addPath(path g) {
+ //makeMutable(); // Manually inlined here for speed reasons.
+ if (base.frozen)
+ base = base.getMutable();
+ base.addPath(g);
+ }
+
+ void addPath(path[] g) {
+ //makeMutable(); // Manually inlined here for speed reasons.
+ if (base.frozen)
+ base = base.getMutable();
+ base.addPath(g);
+ }
+
+ void addPath(path g, pen p) {
+ //makeMutable(); // Manually inlined here for speed reasons.
+ if (base.frozen)
+ base = base.getMutable();
+ base.addPath(g, p);
+ }
+
+ public bool userBoundsAreSet() {
+ return base.userBoundsAreSet();
+ }
+ public pair userMin() {
+ return base.userMin();
+ }
+ public pair userMax() {
+ return base.userMax();
+ }
+ public void alterUserBound(string which, real val) {
+ makeMutable();
+ base.alterUserBound(which, val);
+ }
+
+ void xclip(real Min, real Max) {
+ makeMutable();
+ base.xclip(Min,Max);
+ }
+
+ void yclip(real Min, real Max) {
+ makeMutable();
+ base.yclip(Min,Max);
+ }
+
+ void clip(pair Min, pair Max) {
+ // TODO: If the user bounds have been manually altered, they may be
+ // incorrect after the clip.
+ xclip(Min.x,Max.x);
+ yclip(Min.y,Max.y);
+ }
+
+ pair min(transform t) {
+ return base.min(t);
+ }
+
+ pair max(transform t) {
+ return base.max(t);
+ }
+
+ transform scaling(real xsize, real ysize,
+ real xunitsize, real yunitsize,
+ bool keepAspect, bool warn) {
+ return base.scaling(xsize, ysize, xunitsize, yunitsize, keepAspect, warn);
+ }
+}
+
+bounds operator *(transform t, bounds b) {
+ return b.transformed(t);
+}
diff --git a/Build/source/utils/asymptote/base/plain_constants.asy b/Build/source/utils/asymptote/base/plain_constants.asy
index d1d11b1b1c5..d41cfb770b8 100644
--- a/Build/source/utils/asymptote/base/plain_constants.asy
+++ b/Build/source/utils/asymptote/base/plain_constants.asy
@@ -63,6 +63,8 @@ restricted file stdout=output("");
void none(file file) {}
void endl(file file) {write(file,'\n',flush);}
void newl(file file) {write(file,'\n');}
+void DOSendl(file file) {write(file,'\r\n',flush);}
+void DOSnewl(file file) {write(file,'\r\n');}
void tab(file file) {write(file,'\t');}
void comma(file file) {write(file,',');}
typedef void suffix(file);
diff --git a/Build/source/utils/asymptote/base/plain_pens.asy b/Build/source/utils/asymptote/base/plain_pens.asy
index 5b0bdbd5879..fcf9d31e638 100644
--- a/Build/source/utils/asymptote/base/plain_pens.asy
+++ b/Build/source/utils/asymptote/base/plain_pens.asy
@@ -17,8 +17,8 @@ void defaultpen(real w) {defaultpen(linewidth(w));}
pen operator +(pen p, real w) {return p+linewidth(w);}
pen operator +(real w, pen p) {return linewidth(w)+p;}
-pen Dotted=dotted+1.0;
-pen Dotted(pen p=currentpen) {return dotted+2*linewidth(p);}
+pen Dotted(pen p=currentpen) {return linetype(new real[] {0,3})+2*linewidth(p);}
+pen Dotted=Dotted();
restricted pen squarecap=linecap(0);
restricted pen roundcap=linecap(1);
@@ -129,7 +129,7 @@ pen palegrey=palegray;
pen lightgrey=lightgray;
pen mediumgrey=mediumgray;
pen grey=gray;
-pen heavygrey=gray;
+pen heavygrey=heavygray;
pen deepgrey=deepgray;
pen darkgrey=darkgray;
diff --git a/Build/source/utils/asymptote/base/plain_picture.asy b/Build/source/utils/asymptote/base/plain_picture.asy
index 6764d885380..5b06b7f737c 100644
--- a/Build/source/utils/asymptote/base/plain_picture.asy
+++ b/Build/source/utils/asymptote/base/plain_picture.asy
@@ -1,114 +1,15 @@
-real camerafactor=2; // Factor used for camera adjustment.
+// Pre picture <<<1
+import plain_scaling;
+import plain_bounds;
+
+include plain_prethree;
+
+// This variable is required by asymptote.sty.
pair viewportsize=0; // Horizontal and vertical viewport limits.
restricted bool Aspect=true;
restricted bool IgnoreAspect=false;
-typedef real[][] transform3;
-restricted transform3 identity4=identity(4);
-
-// A uniform 3D scaling.
-transform3 scale3(real s)
-{
- transform3 t=identity(4);
- t[0][0]=t[1][1]=t[2][2]=s;
- return t;
-}
-
-// Simultaneous 3D scalings in the x, y, and z directions.
-transform3 scale(real x, real y, real z)
-{
- transform3 t=identity(4);
- t[0][0]=x;
- t[1][1]=y;
- t[2][2]=z;
- return t;
-}
-
-transform3 shiftless(transform3 t)
-{
- transform3 T=copy(t);
- T[0][3]=T[1][3]=T[2][3]=0;
- return T;
-}
-
-// A coordinate in "flex space." A linear combination of user and true-size
-// coordinates.
-struct coord {
- real user,truesize;
-
- // Build a coord.
- static coord build(real user, real truesize) {
- coord c=new coord;
- c.user=user;
- c.truesize=truesize;
- return c;
- }
-
- // Deep copy of coordinate. Users may add coords to the picture, but then
- // modify the struct. To prevent this from yielding unexpected results, deep
- // copying is used.
- coord copy() {
- return build(user, truesize);
- }
-
- void clip(real min, real max) {
- user=min(max(user,min),max);
- truesize=0;
- }
-}
-
-struct coords2 {
- coord[] x,y;
- void erase() {
- x.delete();
- y.delete();
- }
- // Only a shallow copy of the individual elements of x and y
- // is needed since, once entered, they are never modified.
- coords2 copy() {
- coords2 c=new coords2;
- c.x=copy(x);
- c.y=copy(y);
- return c;
- }
- void append(coords2 c) {
- x.append(c.x);
- y.append(c.y);
- }
- void push(pair user, pair truesize) {
- x.push(coord.build(user.x,truesize.x));
- y.push(coord.build(user.y,truesize.y));
- }
- void push(coord cx, coord cy) {
- x.push(cx);
- y.push(cy);
- }
- void push(transform t, coords2 c1, coords2 c2) {
- for(int i=0; i < c1.x.length; ++i) {
- coord cx=c1.x[i], cy=c2.y[i];
- pair tinf=shiftless(t)*(0,0);
- pair z=t*(cx.user,cy.user);
- pair w=(cx.truesize,cy.truesize);
- w=length(w)*unit(shiftless(t)*w);
- coord Cx,Cy;
- Cx.user=z.x;
- Cy.user=z.y;
- Cx.truesize=w.x;
- Cy.truesize=w.y;
- push(Cx,Cy);
- }
- }
- void xclip(real min, real max) {
- for(int i=0; i < x.length; ++i)
- x[i].clip(min,max);
- }
- void yclip(real min, real max) {
- for(int i=0; i < y.length; ++i)
- y[i].clip(min,max);
- }
-}
-
struct coords3 {
coord[] x,y,z;
void erase() {
@@ -159,89 +60,7 @@ struct coords3 {
}
}
-bool operator <= (coord a, coord b)
-{
- return a.user <= b.user && a.truesize <= b.truesize;
-}
-
-bool operator >= (coord a, coord b)
-{
- return a.user >= b.user && a.truesize >= b.truesize;
-}
-
-// Find the maximal elements of the input array, using the partial ordering
-// given.
-coord[] maxcoords(coord[] in, bool operator <= (coord,coord))
-{
- // As operator <= is defined in the parameter list, it has a special
- // meaning in the body of the function.
-
- coord best;
- coord[] c;
-
- int n=in.length;
-
- if(n == 0)
- return c;
-
- int first=0;
- // Add the first coord without checking restrictions (as there are none).
- best=in[first];
- c.push(best);
-
- static int NONE=-1;
-
- int dominator(coord x)
- {
- // This assumes it has already been checked against the best.
- for(int i=1; i < c.length; ++i)
- if(x <= c[i])
- return i;
- return NONE;
- }
-
- void promote(int i)
- {
- // Swap with the top
- coord x=c[i];
- c[i]=best;
- best=c[0]=x;
- }
-
- void addmaximal(coord x)
- {
- coord[] newc;
-
- // Check if it beats any others.
- for(int i=0; i < c.length; ++i) {
- coord y=c[i];
- if(!(y <= x))
- newc.push(y);
- }
- newc.push(x);
- c=newc;
- best=c[0];
- }
-
- void add(coord x)
- {
- if(x <= best)
- return;
- else {
- int i=dominator(x);
- if(i == NONE)
- addmaximal(x);
- else
- promote(i);
- }
- }
-
- for(int i=1; i < n; ++i)
- add(in[i]);
-
- return c;
-}
-
+// scaleT and Legend <<<
typedef real scalefcn(real x);
struct scaleT {
@@ -328,233 +147,9 @@ struct Legend {
}
}
-pair rectify(pair dir)
-{
- real scale=max(abs(dir.x),abs(dir.y));
- if(scale != 0) dir *= 0.5/scale;
- dir += (0.5,0.5);
- return dir;
-}
-
-pair point(frame f, pair dir)
-{
- pair m=min(f);
- pair M=max(f);
- return m+realmult(rectify(dir),M-m);
-}
-
-path[] align(path[] g, transform t=identity(), pair position,
- pair align, pen p=currentpen)
-{
- if(g.length == 0) return g;
- pair m=min(g);
- pair M=max(g);
- pair dir=rectify(inverse(t)*-align);
- if(basealign(p) == 1)
- dir -= (0,m.y/(M.y-m.y));
- pair a=m+realmult(dir,M-m);
- return shift(position+align*labelmargin(p))*t*shift(-a)*g;
-}
-
-// Returns a transform for aligning frame f in the direction align
-transform shift(frame f, pair align)
-{
- return shift(align-point(f,-align));
-}
-
-// Returns a copy of frame f aligned in the direction align
-frame align(frame f, pair align)
-{
- return shift(f,align)*f;
-}
-
-struct transformation {
- transform3 modelview; // For orientation and positioning
- transform3 projection; // For 3D to 2D projection
- bool infinity;
- void operator init(transform3 modelview) {
- this.modelview=modelview;
- this.projection=identity4;
- infinity=true;
- }
- void operator init(transform3 modelview, transform3 projection) {
- this.modelview=modelview;
- this.projection=projection;
- infinity=false;
- }
- transform3 compute() {
- return infinity ? modelview : projection*modelview;
- }
- transformation copy() {
- transformation T=new transformation;
- T.modelview=copy(modelview);
- T.projection=copy(projection);
- T.infinity=infinity;
- return T;
- }
-}
-
-struct projection {
- transform3 t; // projection*modelview (cached)
- bool infinity;
- bool absolute=false;
- triple camera; // Position of camera.
- triple up; // A vector that should be projected to direction (0,1).
- triple target; // Point where camera is looking at.
- triple normal; // Normal vector from target to projection plane.
- pair viewportshift; // Fractional viewport shift.
- real zoom=1; // Zoom factor.
- real angle; // Lens angle (for perspective projection).
- bool showtarget=true; // Expand bounding volume to include target?
- typedef transformation projector(triple camera, triple up, triple target);
- projector projector;
- bool autoadjust=true; // Adjust camera to lie outside bounding volume?
- bool center=false; // Center target within bounding volume?
- int ninterpolate; // Used for projecting nurbs to 2D Bezier curves.
- bool bboxonly=true; // Typeset label bounding box only.
-
- transformation T;
-
- void calculate() {
- T=projector(camera,up,target);
- t=T.compute();
- infinity=T.infinity;
- ninterpolate=infinity ? 1 : 16;
- }
-
- triple vector() {
- return camera-target;
- }
-
- void operator init(triple camera, triple up=(0,0,1), triple target=(0,0,0),
- triple normal=camera-target,
- real zoom=1, real angle=0, pair viewportshift=0,
- bool showtarget=true, bool autoadjust=true,
- bool center=false, projector projector) {
- this.camera=camera;
- this.up=up;
- this.target=target;
- this.normal=normal;
- this.zoom=zoom;
- this.angle=angle;
- this.viewportshift=viewportshift;
- this.showtarget=showtarget;
- this.autoadjust=autoadjust;
- this.center=center;
- this.projector=projector;
- calculate();
- }
-
- projection copy() {
- projection P=new projection;
- P.t=t;
- P.infinity=infinity;
- P.absolute=absolute;
- P.camera=camera;
- P.up=up;
- P.target=target;
- P.normal=normal;
- P.zoom=zoom;
- P.angle=angle;
- P.viewportshift=viewportshift;
- P.showtarget=showtarget;
- P.autoadjust=autoadjust;
- P.center=center;
- P.projector=projector;
- P.ninterpolate=ninterpolate;
- P.bboxonly=bboxonly;
- P.T=T.copy();
- return P;
- }
-
- // Return the maximum distance of box(m,M) from target.
- real distance(triple m, triple M) {
- triple[] c={m,(m.x,m.y,M.z),(m.x,M.y,m.z),(m.x,M.y,M.z),
- (M.x,m.y,m.z),(M.x,m.y,M.z),(M.x,M.y,m.z),M};
- return max(abs(c-target));
- }
-
- // Move the camera so that the box(m,M) rotated about target will always
- // lie in front of the clipping plane.
- bool adjust(triple m, triple M) {
- triple v=camera-target;
- real d=distance(m,M);
- static real lambda=camerafactor*(1-sqrtEpsilon);
- if(lambda*d >= abs(v)) {
- camera=target+camerafactor*d*unit(v);
- calculate();
- return true;
- }
- return false;
- }
-}
-
-projection currentprojection;
-
-struct light {
- real[][] diffuse;
- real[][] ambient;
- real[][] specular;
- pen background=nullpen; // 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 currently implemented.
-
- transform3 T=identity(4); // Transform to apply to normal vectors.
+// >>>
- bool on() {return position.length > 0;}
-
- void operator init(pen[] diffuse,
- pen[] ambient=array(diffuse.length,black),
- pen[] specular=diffuse, pen background=nullpen,
- real specularfactor=1,
- bool viewport=false, 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.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=false...triple[] position) {
- int n=position.length;
- operator init(array(n,diffuse),array(n,ambient),array(n,specular),
- background,specularfactor,viewport,position);
- }
-
- void operator init(pen diffuse=white, pen ambient=black, pen specular=diffuse,
- pen background=nullpen, bool viewport=false,
- real x, real y, real z) {
- operator init(diffuse,ambient,specular,background,viewport,(x,y,z));
- }
-
- void operator init(explicit light light) {
- diffuse=copy(light.diffuse);
- ambient=copy(light.ambient);
- specular=copy(light.specular);
- background=light.background;
- specularfactor=light.specularfactor;
- viewport=light.viewport;
- position=copy(light.position);
- }
-
- real[] background() {return rgba(background == nullpen ? white : background);}
-}
-
-light currentlight;
+// Frame Alignment was here
triple min3(pen p)
{
@@ -571,9 +166,34 @@ triple max3(pen p)
typedef void drawer(frame f, transform t);
// A generalization of drawer that includes the final frame's bounds.
+// TODO: Add documentation as to what T is.
typedef void drawerBound(frame f, transform t, transform T, pair lb, pair rt);
-struct picture {
+// PairOrTriple <<<1
+// This struct is used to represent a userMin/userMax which serves as both a
+// pair and a triple depending on the context.
+struct pairOrTriple {
+ real x,y,z;
+ void init() { x = y = z = 0; }
+};
+void copyPairOrTriple(pairOrTriple dest, pairOrTriple src)
+{
+ dest.x = src.x;
+ dest.y = src.y;
+ dest.z = src.z;
+}
+pair operator cast (pairOrTriple a) {
+ return (a.x, a.y);
+};
+triple operator cast (pairOrTriple a) {
+ return (a.x, a.y, a.z);
+}
+void write(pairOrTriple a) {
+ write((triple) a);
+}
+
+struct picture { // <<<1
+ // Nodes <<<2
// Three-dimensional version of drawer and drawerBound:
typedef void drawer3(frame f, transform3 t, picture pic, projection P);
typedef void drawerBound3(frame f, transform3 t, transform3 T,
@@ -585,39 +205,6 @@ struct picture {
bool uptodate=true;
- // The coordinates in flex space to be used in sizing the picture.
- struct bounds {
- coords2 point,min,max;
- bool exact=true; // An accurate picture bounds is provided by the user.
- void erase() {
- point.erase();
- min.erase();
- max.erase();
- }
- bounds copy() {
- bounds b=new bounds;
- b.point=point.copy();
- b.min=min.copy();
- b.max=max.copy();
- b.exact=exact;
- return b;
- }
- void xclip(real Min, real Max) {
- point.xclip(Min,Max);
- min.xclip(Min,Max);
- max.xclip(Min,Max);
- }
- void yclip(real Min, real Max) {
- point.yclip(Min,Max);
- min.yclip(Min,Max);
- max.yclip(Min,Max);
- }
- void clip(triple Min, triple Max) {
- xclip(Min.x,Max.x);
- yclip(Min.y,Max.y);
- }
- }
-
struct bounds3 {
coords3 point,min,max;
bool exact=true; // An accurate picture bounds is provided by the user.
@@ -639,14 +226,15 @@ struct picture {
bounds bounds;
bounds3 bounds3;
+ // Other Fields <<<2
// Transform to be applied to this picture.
transform T;
transform3 T3;
- // Cached user-space bounding box
- triple userMin,userMax;
- bool userSetx,userSety,userSetz;
-
+ // The internal representation of the 3D user bounds.
+ private pairOrTriple umin, umax;
+ private bool usetx, usety, usetz;
+
ScaleT scale; // Needed by graph
Legend[] legend;
@@ -669,9 +257,11 @@ struct picture {
bool fixed;
transform fixedscaling;
+ // Init and erase <<<2
void init() {
- userMin=userMax=(0,0,0);
- userSetx=userSety=userSetz=false;
+ umin.init();
+ umax.init();
+ usetx=usety=usetz=false;
T3=identity(4);
}
init();
@@ -688,6 +278,7 @@ struct picture {
init();
}
+ // Empty <<<2
bool empty2() {
return nodes.length == 0;
}
@@ -700,133 +291,175 @@ struct picture {
return empty2() && empty3();
}
- pair userMin() {return (userMin.x,userMin.y);}
- pair userMax() {return (userMax.x,userMax.y);}
+ // User min/max <<<2
+ pair userMin2() {return bounds.userMin(); }
+ pair userMax2() {return bounds.userMax(); }
- void userMinx(real x) {
- userMin=(x,userMin.y,userMin.z);
- userSetx=true;
+ bool userSetx2() { return bounds.userBoundsAreSet(); }
+ bool userSety2() { return bounds.userBoundsAreSet(); }
+
+ triple userMin3() { return umin; }
+ triple userMax3() { return umax; }
+
+ bool userSetx3() { return usetx; }
+ bool userSety3() { return usety; }
+ bool userSetz3() { return usetz; }
+
+ private typedef real binop(real, real);
+
+ // Helper functions for finding the minimum/maximum of two data, one of
+ // which may not be defined.
+ private static real merge(real x1, bool set1, real x2, bool set2, binop m)
+ {
+ return set1 ? (set2 ? m(x1,x2) : x1) : x2;
}
-
- void userMiny(real y) {
- userMin=(userMin.x,y,userMin.z);
- userSety=true;
+ private pairOrTriple userExtreme(pair u2(), triple u3(), binop m)
+ {
+ bool setx2 = userSetx2();
+ bool sety2 = userSety2();
+ bool setx3 = userSetx3();
+ bool sety3 = userSety3();
+
+ pair p;
+ if (setx2 || sety2)
+ p = u2();
+ triple t = u3();
+
+ pairOrTriple r;
+ r.x = merge(p.x, setx2, t.x, setx3, m);
+ r.y = merge(p.y, sety2, t.y, sety3, m);
+ r.z = t.z;
+
+ return r;
}
-
- void userMinz(real z) {
- userMin=(userMin.x,userMin.y,z);
- userSetz=true;
+
+ // The combination of 2D and 3D data.
+ pairOrTriple userMin() {
+ return userExtreme(userMin2, userMin3, min);
}
-
- void userMaxx(real x) {
- userMax=(x,userMax.y,userMax.z);
- userSetx=true;
+ pairOrTriple userMax() {
+ return userExtreme(userMax2, userMax3, max);
+ }
+
+ bool userSetx() { return userSetx2() || userSetx3(); }
+ bool userSety() { return userSety2() || userSety3(); }
+ bool userSetz() = userSetz3;
+
+ // Functions for setting the user bounds.
+ void userMinx3(real x) {
+ umin.x=x;
+ usetx=true;
}
- void userMaxy(real y) {
- userMax=(userMax.x,y,userMax.z);
- userSety=true;
+ void userMiny3(real y) {
+ umin.y=y;
+ usety=true;
}
- void userMaxz(real z) {
- userMax=(userMax.x,userMax.y,z);
- userSetz=true;
+ void userMinz3(real z) {
+ umin.z=z;
+ usetz=true;
}
- void userCorners(pair c00, pair c01, pair c10, pair c11) {
- userMin=(min(c00.x,c01.x,c10.x,c11.x),min(c00.y,c01.y,c10.y,c11.y),
- userMin.z);
- userMax=(max(c00.x,c01.x,c10.x,c11.x),max(c00.y,c01.y,c10.y,c11.y),
- userMax.z);
+ void userMaxx3(real x) {
+ umax.x=x;
+ usetx=true;
}
- void userCorners(triple c000, triple c001, triple c010, triple c011,
- triple c100, triple c101, triple c110, triple c111) {
- userMin=(min(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x),
- min(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y),
- min(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z));
- userMax=(max(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x),
- max(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y),
- max(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z));
+ void userMaxy3(real y) {
+ umax.y=y;
+ usety=true;
}
- void userCopy(picture pic) {
- userMin=(triple) pic.userMin;
- userMax=(triple) pic.userMax;
- userSetx=pic.userSetx;
- userSety=pic.userSety;
- userSetz=pic.userSetz;
+ void userMaxz3(real z) {
+ umax.z=z;
+ usetz=true;
+ }
+
+ void userMinx2(real x) { bounds.alterUserBound("minx", x); }
+ void userMinx(real x) { userMinx2(x); userMinx3(x); }
+ void userMiny2(real y) { bounds.alterUserBound("miny", y); }
+ void userMiny(real y) { userMiny2(y); userMiny3(y); }
+ void userMaxx2(real x) { bounds.alterUserBound("maxx", x); }
+ void userMaxx(real x) { userMaxx2(x); userMaxx3(x); }
+ void userMaxy2(real y) { bounds.alterUserBound("maxy", y); }
+ void userMaxy(real y) { userMaxy2(y); userMaxy3(y); }
+ void userMinz(real z) = userMinz3;
+ void userMaxz(real z) = userMaxz3;
+
+ void userCorners3(triple c000, triple c001, triple c010, triple c011,
+ triple c100, triple c101, triple c110, triple c111) {
+ umin.x = min(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x);
+ umin.y = min(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y);
+ umin.z = min(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z);
+ umax.x = max(c000.x,c001.x,c010.x,c011.x,c100.x,c101.x,c110.x,c111.x);
+ umax.y = max(c000.y,c001.y,c010.y,c011.y,c100.y,c101.y,c110.y,c111.y);
+ umax.z = max(c000.z,c001.z,c010.z,c011.z,c100.z,c101.z,c110.z,c111.z);
}
- typedef real binop(real, real);
-
// Cache the current user-space bounding box x coodinates
- void userBoxX(real min, real max, binop m=min, binop M=max) {
- if(userSetx) {
- userMin=(m(userMin.x,min),userMin.y,userMin.z);
- userMax=(M(userMax.x,max),userMax.y,userMax.z);
+ void userBoxX3(real min, real max, binop m=min, binop M=max) {
+ if (usetx) {
+ umin.x=m(umin.x,min);
+ umax.x=M(umax.x,max);
} else {
- userMin=(min,userMin.y,userMin.z);
- userMax=(max,userMax.y,userMax.z);
- userSetx=true;
+ umin.x=min;
+ umax.x=max;
+ usetx=true;
}
}
-
+
// Cache the current user-space bounding box y coodinates
- void userBoxY(real min, real max, binop m=min, binop M=max) {
- if(userSety) {
- userMin=(userMin.x,m(userMin.y,min),userMin.z);
- userMax=(userMax.x,M(userMax.y,max),userMax.z);
+ void userBoxY3(real min, real max, binop m=min, binop M=max) {
+ if (usety) {
+ umin.y=m(umin.y,min);
+ umax.y=M(umax.y,max);
} else {
- userMin=(userMin.x,min,userMin.z);
- userMax=(userMax.x,max,userMax.z);
- userSety=true;
+ umin.y=min;
+ umax.y=max;
+ usety=true;
}
}
-
+
// Cache the current user-space bounding box z coodinates
- void userBoxZ(real min, real max, binop m=min, binop M=max) {
- if(userSetz) {
- userMin=(userMin.x,userMin.y,m(userMin.z,min));
- userMax=(userMax.x,userMax.y,M(userMax.z,max));
+ void userBoxZ3(real min, real max, binop m=min, binop M=max) {
+ if (usetz) {
+ umin.z=m(umin.z,min);
+ umax.z=M(umax.z,max);
} else {
- userMin=(userMin.x,userMin.y,min);
- userMax=(userMax.x,userMax.y,max);
- userSetz=true;
+ umin.z=min;
+ umax.z=max;
+ usetz=true;
}
}
-
- // Cache the current user-space bounding box
- void userBox(pair min, pair max) {
- userBoxX(min.x,max.x);
- userBoxY(min.y,max.y);
- }
-
+
// Cache the current user-space bounding box
- void userBox(triple min, triple max) {
- userBoxX(min.x,max.x);
- userBoxY(min.y,max.y);
- userBoxZ(min.z,max.z);
+ void userBox3(triple min, triple max) {
+ userBoxX3(min.x,max.x);
+ userBoxY3(min.y,max.y);
+ userBoxZ3(min.z,max.z);
}
- // Clip the current user-space bounding box
- void userClip(pair min, pair max) {
- userBoxX(min.x,max.x,max,min);
- userBoxY(min.y,max.y,max,min);
+ // Add drawer <<<2
+ void add(drawerBound d, bool exact=false, bool above=true) {
+ uptodate=false;
+ if(!exact) bounds.exact=false;
+ if(above)
+ nodes.push(d);
+ else
+ nodes.insert(0,d);
}
- void add(drawerBound d, bool exact=false) {
+ // Faster implementation of most common case.
+ void addExactAbove(drawerBound d) {
uptodate=false;
- if(!exact) bounds.exact=false;
nodes.push(d);
}
void add(drawer d, bool exact=false, bool above=true) {
- uptodate=false;
- if(!exact) bounds.exact=false;
- nodes.push(new void(frame f, transform t, transform T, pair, pair) {
+ add(new void(frame f, transform t, transform T, pair, pair) {
d(f,t*T);
- });
+ },exact,above);
}
void add(drawerBound3 d, bool exact=false, bool above=true) {
@@ -845,20 +478,22 @@ struct picture {
},exact,above);
}
- void clip(drawer d, bool exact=false) {
- bounds.clip(userMin,userMax);
+ // Clip <<<2
+ void clip(pair min, pair max, drawer d, bool exact=false) {
+ bounds.clip(min, max);
this.add(d,exact);
}
- void clip(drawerBound d, bool exact=false) {
- bounds.clip(userMin,userMax);
+ void clip(pair min, pair max, drawerBound d, bool exact=false) {
+ bounds.clip(min, max);
this.add(d,exact);
}
+ // Add sizing <<<2
// Add a point to the sizing.
void addPoint(pair user, pair truesize=0) {
- bounds.point.push(user,truesize);
- userBox(user,user);
+ bounds.addPoint(user,truesize);
+ //userBox(user,user);
}
// Add a point to the sizing, accounting also for the size of the pen.
@@ -869,7 +504,7 @@ struct picture {
void addPoint(triple user, triple truesize=(0,0,0)) {
bounds3.point.push(user,truesize);
- userBox(user,user);
+ userBox3(user,user);
}
void addPoint(triple user, triple truesize=(0,0,0), pen p) {
@@ -879,34 +514,21 @@ struct picture {
// Add a box to the sizing.
void addBox(pair userMin, pair userMax, pair trueMin=0, pair trueMax=0) {
- bounds.min.push(userMin,trueMin);
- bounds.max.push(userMax,trueMax);
- userBox(userMin,userMax);
+ bounds.addBox(userMin, userMax, trueMin, trueMax);
}
void addBox(triple userMin, triple userMax, triple trueMin=(0,0,0),
triple trueMax=(0,0,0)) {
bounds3.min.push(userMin,trueMin);
bounds3.max.push(userMax,trueMax);
- userBox(userMin,userMax);
- }
-
- // Add a (user space) path to the sizing.
- void addPath(path g) {
- if(size(g) > 0)
- addBox(min(g),max(g));
- }
- void addPath(path[] g) {
- for(int i=0; i < g.length; ++i)
- addPath(g[i]);
+ userBox3(userMin,userMax);
}
- // Add a path to the sizing with the additional padding of a pen.
- void addPath(path g, pen p) {
- if(size(g) > 0)
- addBox(min(g),max(g),min(p),max(p));
- }
+ // For speed reason, we unravel the addPath routines from bounds. This
+ // avoids an extra function call.
+ from bounds unravel addPath;
+ // Size commands <<<2
void size(real x, real y=x, bool keepAspect=this.keepAspect) {
if(!empty()) uptodate=false;
xsize=x;
@@ -929,62 +551,15 @@ struct picture {
zunitsize=z;
}
- // The scaling in one dimension: x --> a*x + b
- struct scaling {
- real a,b;
- static scaling build(real a, real b) {
- scaling s=new scaling;
- s.a=a; s.b=b;
- return s;
- }
- real scale(real x) {
- return a*x+b;
- }
- real scale(coord c) {
- return scale(c.user) + c.truesize;
- }
- }
-
- // Calculate the minimum point in scaling the coords.
- real min(real m, scaling s, coord[] c) {
- for(int i=0; i < c.length; ++i)
- if(s.scale(c[i]) < m)
- m=s.scale(c[i]);
- return m;
- }
-
- // Calculate the maximum point in scaling the coords.
- real max(real M, scaling s, coord[] c) {
- for(int i=0; i < c.length; ++i)
- if(s.scale(c[i]) > M)
- M=s.scale(c[i]);
- return M;
- }
-
+ // min/max of picture <<<2
// Calculate the min for the final frame, given the coordinate transform.
pair min(transform t) {
- if(bounds.min.x.length == 0 && bounds.point.x.length == 0 &&
- bounds.max.x.length == 0) return 0;
- pair a=t*(1,1)-t*(0,0), b=t*(0,0);
- scaling xs=scaling.build(a.x,b.x);
- scaling ys=scaling.build(a.y,b.y);
- return (min(min(min(infinity,xs,bounds.point.x),xs,bounds.min.x),
- xs,bounds.max.x),
- min(min(min(infinity,ys,bounds.point.y),ys,bounds.min.y),
- ys,bounds.max.y));
+ return bounds.min(t);
}
// Calculate the max for the final frame, given the coordinate transform.
pair max(transform t) {
- if(bounds.min.x.length == 0 && bounds.point.x.length == 0 &&
- bounds.max.x.length == 0) return 0;
- pair a=t*(1,1)-t*(0,0), b=t*(0,0);
- scaling xs=scaling.build(a.x,b.x);
- scaling ys=scaling.build(a.y,b.y);
- return (max(max(max(-infinity,xs,bounds.point.x),xs,bounds.min.x),
- xs,bounds.max.x),
- max(max(max(-infinity,ys,bounds.point.y),ys,bounds.min.y),
- ys,bounds.max.y));
+ return bounds.max(t);
}
// Calculate the min for the final frame, given the coordinate transform.
@@ -1019,66 +594,6 @@ struct picture {
zs,bounds3.max.z));
}
- // Calculate the sizing constants for the given array and maximum size.
- real calculateScaling(string dir, coord[] coords, real size,
- bool warn=true) {
- access simplex;
- simplex.problem p=new simplex.problem;
-
- void addMinCoord(coord c) {
- // (a*user + b) + truesize >= 0:
- p.addRestriction(c.user,1,c.truesize);
- }
- void addMaxCoord(coord c) {
- // (a*user + b) + truesize <= size:
- p.addRestriction(-c.user,-1,size-c.truesize);
- }
-
- coord[] m=maxcoords(coords,operator >=);
- coord[] M=maxcoords(coords,operator <=);
-
- for(int i=0; i < m.length; ++i)
- addMinCoord(m[i]);
- for(int i=0; i < M.length; ++i)
- addMaxCoord(M[i]);
-
- int status=p.optimize();
- if(status == simplex.problem.OPTIMAL) {
- return scaling.build(p.a(),p.b()).a;
- } else if(status == simplex.problem.UNBOUNDED) {
- if(warn) warning("unbounded",dir+" scaling in picture unbounded");
- return 0;
- } else {
- if(!warn) return 1;
- bool userzero=true;
- for(int i=0; i < coords.length; ++i) {
- if(coords[i].user != 0) userzero=false;
- }
- if(userzero) return 1;
- warning("cannotfit","cannot fit picture to "+dir+"size "+(string) size
- +"...enlarging...");
- return calculateScaling(dir,coords,sqrt(2)*size,warn);
- }
- }
-
- void append(coords2 point, coords2 min, coords2 max, transform t,
- bounds bounds)
- {
- // Add the coord info to this picture.
- if(t == identity()) {
- point.append(bounds.point);
- min.append(bounds.min);
- max.append(bounds.max);
- } else {
- point.push(t,bounds.point,bounds.point);
- // Add in all 4 corner points, to properly size rectangular pictures.
- point.push(t,bounds.min,bounds.min);
- point.push(t,bounds.min,bounds.max);
- point.push(t,bounds.max,bounds.min);
- point.push(t,bounds.max,bounds.max);
- }
- }
-
void append(coords3 point, coords3 min, coords3 max, transform3 t,
bounds3 bounds)
{
@@ -1101,37 +616,13 @@ struct picture {
}
}
+ // Scaling and Fit <<<2
// Returns the transform for turning user-space pairs into true-space pairs.
transform scaling(real xsize, real ysize, bool keepAspect=true,
bool warn=true) {
- if(xsize == 0 && xunitsize == 0 && ysize == 0 && yunitsize == 0)
- return identity();
-
- coords2 Coords;
-
- append(Coords,Coords,Coords,T,bounds);
-
- real sx;
- if(xunitsize == 0) {
- if(xsize != 0) sx=calculateScaling("x",Coords.x,xsize,warn);
- } else sx=xunitsize;
-
- real sy;
- if(yunitsize == 0) {
- if(ysize != 0) sy=calculateScaling("y",Coords.y,ysize,warn);
- } else sy=yunitsize;
-
- if(sx == 0) {
- sx=sy;
- if(sx == 0)
- return identity();
- } else if(sy == 0) sy=sx;
+ bounds b = (T == identity()) ? this.bounds : T * this.bounds;
-
- if(keepAspect && (xunitsize == 0 || yunitsize == 0))
- return scale(min(sx,sy));
- else
- return scale(sx,sy);
+ return b.scaling(xsize, ysize, xunitsize, yunitsize, keepAspect, warn);
}
transform scaling(bool warn=true) {
@@ -1184,7 +675,8 @@ struct picture {
frame fit(transform t, transform T0=T, pair m, pair M) {
frame f;
- for(int i=0; i < nodes.length; ++i)
+ int n = nodes.length;
+ for(int i=0; i < n; ++i)
nodes[i](f,t,T0,m,M);
return f;
}
@@ -1207,6 +699,7 @@ struct picture {
return fit3(t,pic,P,min(t),max(t));
}
+ // Add drawer wrappers <<<2
void add(void d(picture, transform), bool exact=false) {
add(new void(frame f, transform t) {
picture opic=new picture;
@@ -1233,6 +726,7 @@ struct picture {
},exact,above);
}
+ // More scaling <<<2
frame scaled() {
frame f=fit(fixedscaling);
pair d=size(f);
@@ -1289,6 +783,7 @@ struct picture {
} else return scale(xgrow,ygrow,zgrow);
}
+ // calculateTransform with scaling <<<2
// Return the transform that would be used to fit the picture to a frame
transform calculateTransform(real xsize, real ysize, bool keepAspect=true,
bool warn=true) {
@@ -1309,6 +804,8 @@ struct picture {
return scale3(fit3(t,null,P),keepAspect)*t;
}
+ // min/max with xsize and ysize <<<2
+ // NOTE: These are probably very slow as implemented.
pair min(real xsize=this.xsize, real ysize=this.ysize,
bool keepAspect=this.keepAspect, bool warn=true) {
return min(calculateTransform(xsize,ysize,keepAspect,warn));
@@ -1331,11 +828,14 @@ struct picture {
return max(calculateTransform3(xsize,ysize,zsize,keepAspect,warn,P));
}
+ // More Fitting <<<2
// Returns the 2D picture fit to the requested size.
frame fit2(real xsize=this.xsize, real ysize=this.ysize,
bool keepAspect=this.keepAspect) {
if(fixed) return scaled();
- if(empty2()) return newframe;
+ if(empty2())
+ return newframe;
+
transform t=scaling(xsize,ysize,keepAspect);
frame f=fit(t);
transform s=scale(f,xsize,ysize,keepAspect);
@@ -1378,15 +878,42 @@ struct picture {
return s*f;
}
+ // Copying <<<2
+
+ // Copies enough information to yield the same userMin/userMax.
+ void userCopy2(picture pic) {
+ userMinx2(pic.userMin2().x);
+ userMiny2(pic.userMin2().y);
+ userMaxx2(pic.userMax2().x);
+ userMaxy2(pic.userMax2().y);
+ }
+
+ void userCopy3(picture pic) {
+ copyPairOrTriple(umin, pic.umin);
+ copyPairOrTriple(umax, pic.umax);
+ usetx=pic.usetx;
+ usety=pic.usety;
+ usetz=pic.usetz;
+ }
+
+ void userCopy(picture pic) {
+ userCopy2(pic);
+ userCopy3(pic);
+ }
+
// Copies the drawing information, but not the sizing information into a new
// picture. Fitting this picture will not scale as the original picture would.
picture drawcopy() {
picture dest=new picture;
- dest.nodes=copy(nodes);
+ dest.nodes = copy(nodes);
dest.nodes3=copy(nodes3);
dest.T=T;
dest.T3=T3;
- dest.userCopy(this);
+
+ // TODO: User bounds are sizing info, which probably shouldn't be part of
+ // a draw copy. Should we move this down to copy()?
+ dest.userCopy3(this);
+
dest.scale=scale.copy();
dest.legend=copy(legend);
@@ -1412,6 +939,37 @@ struct picture {
return dest;
}
+ // Helper function for defining transformed pictures. Do not call it
+ // directly.
+ picture transformed(transform t) {
+ picture dest=drawcopy();
+
+ // Replace nodes with a single drawer that realizes the transform.
+ drawerBound[] oldnodes = dest.nodes;
+ void drawAll(frame f, transform tt, transform T, pair lb, pair rt) {
+ transform Tt = T*t;
+ for (var node : oldnodes)
+ node(f, tt, Tt, lb, rt);
+ }
+ dest.nodes = new drawerBound[] { drawAll };
+
+ dest.uptodate=uptodate;
+ dest.bounds=bounds.transformed(t);
+ dest.bounds3=bounds3.copy();
+
+ dest.bounds.exact=false;
+
+ dest.xsize=xsize; dest.ysize=ysize;
+ dest.xsize3=xsize; dest.ysize3=ysize3; dest.zsize3=zsize3;
+ dest.keepAspect=keepAspect;
+ dest.xunitsize=xunitsize; dest.yunitsize=yunitsize;
+ dest.zunitsize=zunitsize;
+ dest.fixed=fixed; dest.fixedscaling=fixedscaling;
+
+ return dest;
+ }
+
+ // Add Picture <<<2
// Add a picture to this picture, such that the user coordinates will be
// scaled identically when fitted
void add(picture src, bool group=true, filltype filltype=NoFill,
@@ -1440,42 +998,38 @@ struct picture {
legend.append(src.legend);
- if(src.userSetx) userBoxX(src.userMin.x,src.userMax.x);
- if(src.userSety) userBoxY(src.userMin.y,src.userMax.y);
- if(src.userSetz) userBoxZ(src.userMin.z,src.userMax.z);
+ if(src.usetx) userBoxX3(src.umin.x,src.umax.x);
+ if(src.usety) userBoxY3(src.umin.y,src.umax.y);
+ if(src.usetz) userBoxZ3(src.umin.z,src.umax.z);
- append(bounds.point,bounds.min,bounds.max,srcCopy.T,src.bounds);
+ bounds.append(srcCopy.T, src.bounds);
+ //append(bounds.point,bounds.min,bounds.max,srcCopy.T,src.bounds);
append(bounds3.point,bounds3.min,bounds3.max,srcCopy.T3,src.bounds3);
- if(!src.bounds.exact) bounds.exact=false;
+ //if(!src.bounds.exact) bounds.exact=false;
if(!src.bounds3.exact) bounds3.exact=false;
}
}
+// Post Struct <<<1
picture operator * (transform t, picture orig)
{
- picture pic=orig.copy();
- pic.T=t*pic.T;
- pic.userCorners(t*(pic.userMin.x,pic.userMin.y),
- t*(pic.userMin.x,pic.userMax.y),
- t*(pic.userMax.x,pic.userMin.y),
- t*(pic.userMax.x,pic.userMax.y));
- pic.bounds.exact=false;
- return pic;
+ return orig.transformed(t);
}
picture operator * (transform3 t, picture orig)
{
picture pic=orig.copy();
pic.T3=t*pic.T3;
- pic.userCorners(t*pic.userMin,
- t*(pic.userMin.x,pic.userMin.y,pic.userMax.z),
- t*(pic.userMin.x,pic.userMax.y,pic.userMin.z),
- t*(pic.userMin.x,pic.userMax.y,pic.userMax.z),
- t*(pic.userMax.x,pic.userMin.y,pic.userMin.z),
- t*(pic.userMax.x,pic.userMin.y,pic.userMax.z),
- t*(pic.userMax.x,pic.userMax.y,pic.userMin.z),
- t*pic.userMax);
+ triple umin=pic.userMin3(), umax=pic.userMax3();
+ pic.userCorners3(t*umin,
+ t*(umin.x,umin.y,umax.z),
+ t*(umin.x,umax.y,umin.z),
+ t*(umin.x,umax.y,umax.z),
+ t*(umax.x,umin.y,umin.z),
+ t*(umax.x,umin.y,umax.z),
+ t*(umax.x,umax.y,umin.z),
+ t*umax);
pic.bounds3.exact=false;
return pic;
}
@@ -1538,9 +1092,54 @@ pair size(picture pic, bool user=false)
return t*M-t*m;
}
+// Frame Alignment <<<
+pair rectify(pair dir)
+{
+ real scale=max(abs(dir.x),abs(dir.y));
+ if(scale != 0) dir *= 0.5/scale;
+ dir += (0.5,0.5);
+ return dir;
+}
+
+pair point(frame f, pair dir)
+{
+ pair m=min(f);
+ pair M=max(f);
+ return m+realmult(rectify(dir),M-m);
+}
+
+path[] align(path[] g, transform t=identity(), pair position,
+ pair align, pen p=currentpen)
+{
+ if(g.length == 0) return g;
+ pair m=min(g);
+ pair M=max(g);
+ pair dir=rectify(inverse(t)*-align);
+ if(basealign(p) == 1)
+ dir -= (0,m.y/(M.y-m.y));
+ pair a=m+realmult(dir,M-m);
+ return shift(position+align*labelmargin(p))*t*shift(-a)*g;
+}
+
+// Returns a transform for aligning frame f in the direction align
+transform shift(frame f, pair align)
+{
+ return shift(align-point(f,-align));
+}
+
+// Returns a copy of frame f aligned in the direction align
+frame align(frame f, pair align)
+{
+ return shift(f,align)*f;
+}
+// >>>
+
pair point(picture pic=currentpicture, pair dir, bool user=true)
{
- pair z=pic.userMin()+realmult(rectify(dir),pic.userMax()-pic.userMin());
+ pair umin = pic.userMin2();
+ pair umax = pic.userMax2();
+
+ pair z=umin+realmult(rectify(dir),umax-umin);
return user ? z : pic.calculateTransform()*z;
}
@@ -1556,7 +1155,7 @@ pair truepoint(picture pic=currentpicture, pair dir, bool user=true)
// Transform coordinate in [0,1]x[0,1] to current user coordinates.
pair relative(picture pic=currentpicture, pair z)
{
- return pic.userMin()+realmult(z,pic.userMax()-pic.userMin());
+ return pic.userMin2()+realmult(z,pic.userMax2()-pic.userMin2());
}
void add(picture pic=currentpicture, drawer d, bool exact=false)
@@ -1604,17 +1203,25 @@ void Draw(picture pic=currentpicture, path g, pen p=currentpen)
pic.addPath(g,p);
}
-void _draw(picture pic=currentpicture, path g, pen p=currentpen,
- margin margin=NoMargin)
+// Default arguments have been removed to increase speed.
+void _draw(picture pic, path g, pen p, margin margin)
{
- pic.add(new void(frame f, transform t) {
- draw(f,margin(t*g,p).g,p);
- },true);
+ if (size(nib(p)) == 0 && margin==NoMargin) {
+ // Inline the drawerBound wrapper for speed.
+ pic.addExactAbove(new void(frame f, transform t, transform T, pair, pair) {
+ _draw(f,t*T*g,p);
+ });
+ } else {
+ pic.add(new void(frame f, transform t) {
+ draw(f,margin(t*g,p).g,p);
+ },true);
+ }
pic.addPath(g,p);
}
void Draw(picture pic=currentpicture, explicit path[] g, pen p=currentpen)
{
+ // Could optimize this by adding one drawer.
for(int i=0; i < g.length; ++i) Draw(pic,g[i],p);
}
@@ -1791,10 +1398,12 @@ void clip(picture pic=currentpicture, path[] g, bool stroke=false,
{
if(copy)
g=copy(g);
- pic.userClip(min(g),max(g));
- pic.clip(new void(frame f, transform t) {
- clip(f,t*g,stroke,fillrule,false);
- },true);
+ //pic.userClip(min(g),max(g));
+ pic.clip(min(g), max(g),
+ new void(frame f, transform t) {
+ clip(f,t*g,stroke,fillrule,false);
+ },
+ true);
}
void beginclip(picture pic=currentpicture, path[] g, bool stroke=false,
@@ -1813,11 +1422,26 @@ void beginclip(picture pic=currentpicture, path[] g, bool stroke=false,
void endclip(picture pic=currentpicture)
{
- if(pic.clipmin.length > 0 && pic.clipmax.length > 0)
- pic.userClip(pic.clipmin.pop(),pic.clipmax.pop());
- pic.clip(new void(frame f, transform) {
- endclip(f);
- },true);
+ pair min,max;
+ if (pic.clipmin.length > 0 && pic.clipmax.length > 0)
+ {
+ min = pic.clipmin.pop();
+ max = pic.clipmax.pop();
+ }
+ else
+ {
+ // We should probably abort here, since the PostScript output will be
+ // garbage.
+ warning("endclip", "endclip without beginclip");
+ min = pic.userMin2();
+ max = pic.userMax2();
+ }
+
+ pic.clip(min, max,
+ new void(frame f, transform) {
+ endclip(f);
+ },
+ true);
}
void unfill(picture pic=currentpicture, path[] g, bool copy=true)
diff --git a/Build/source/utils/asymptote/base/plain_prethree.asy b/Build/source/utils/asymptote/base/plain_prethree.asy
new file mode 100644
index 00000000000..595bac2fad4
--- /dev/null
+++ b/Build/source/utils/asymptote/base/plain_prethree.asy
@@ -0,0 +1,224 @@
+// Critical definitions for transform3 needed by projection and picture.
+
+typedef real[][] transform3;
+restricted transform3 identity4=identity(4);
+
+// A uniform 3D scaling.
+transform3 scale3(real s)
+{
+ transform3 t=identity(4);
+ t[0][0]=t[1][1]=t[2][2]=s;
+ return t;
+}
+
+// Simultaneous 3D scalings in the x, y, and z directions.
+transform3 scale(real x, real y, real z)
+{
+ transform3 t=identity(4);
+ t[0][0]=x;
+ t[1][1]=y;
+ t[2][2]=z;
+ return t;
+}
+
+transform3 shiftless(transform3 t)
+{
+ transform3 T=copy(t);
+ T[0][3]=T[1][3]=T[2][3]=0;
+ return T;
+}
+
+real camerafactor=2; // Factor used for camera adjustment.
+
+struct transformation {
+ transform3 modelview; // For orientation and positioning
+ transform3 projection; // For 3D to 2D projection
+ bool infinity;
+ void operator init(transform3 modelview) {
+ this.modelview=modelview;
+ this.projection=identity4;
+ infinity=true;
+ }
+ void operator init(transform3 modelview, transform3 projection) {
+ this.modelview=modelview;
+ this.projection=projection;
+ infinity=false;
+ }
+ transform3 compute() {
+ return infinity ? modelview : projection*modelview;
+ }
+ transformation copy() {
+ transformation T=new transformation;
+ T.modelview=copy(modelview);
+ T.projection=copy(projection);
+ T.infinity=infinity;
+ return T;
+ }
+}
+
+struct projection {
+ transform3 t; // projection*modelview (cached)
+ bool infinity;
+ bool absolute=false;
+ triple camera; // Position of camera.
+ triple up; // A vector that should be projected to direction (0,1).
+ triple target; // Point where camera is looking at.
+ triple normal; // Normal vector from target to projection plane.
+ pair viewportshift; // Fractional viewport shift.
+ real zoom=1; // Zoom factor.
+ real angle; // Lens angle (for perspective projection).
+ bool showtarget=true; // Expand bounding volume to include target?
+ typedef transformation projector(triple camera, triple up, triple target);
+ projector projector;
+ bool autoadjust=true; // Adjust camera to lie outside bounding volume?
+ bool center=false; // Center target within bounding volume?
+ int ninterpolate; // Used for projecting nurbs to 2D Bezier curves.
+ bool bboxonly=true; // Typeset label bounding box only.
+
+ transformation T;
+
+ void calculate() {
+ T=projector(camera,up,target);
+ t=T.compute();
+ infinity=T.infinity;
+ ninterpolate=infinity ? 1 : 16;
+ }
+
+ triple vector() {
+ return camera-target;
+ }
+
+ void operator init(triple camera, triple up=(0,0,1), triple target=(0,0,0),
+ triple normal=camera-target,
+ real zoom=1, real angle=0, pair viewportshift=0,
+ bool showtarget=true, bool autoadjust=true,
+ bool center=false, projector projector) {
+ this.camera=camera;
+ this.up=up;
+ this.target=target;
+ this.normal=normal;
+ this.zoom=zoom;
+ this.angle=angle;
+ this.viewportshift=viewportshift;
+ this.showtarget=showtarget;
+ this.autoadjust=autoadjust;
+ this.center=center;
+ this.projector=projector;
+ calculate();
+ }
+
+ projection copy() {
+ projection P=new projection;
+ P.t=t;
+ P.infinity=infinity;
+ P.absolute=absolute;
+ P.camera=camera;
+ P.up=up;
+ P.target=target;
+ P.normal=normal;
+ P.zoom=zoom;
+ P.angle=angle;
+ P.viewportshift=viewportshift;
+ P.showtarget=showtarget;
+ P.autoadjust=autoadjust;
+ P.center=center;
+ P.projector=projector;
+ P.ninterpolate=ninterpolate;
+ P.bboxonly=bboxonly;
+ P.T=T.copy();
+ return P;
+ }
+
+ // Return the maximum distance of box(m,M) from target.
+ real distance(triple m, triple M) {
+ triple[] c={m,(m.x,m.y,M.z),(m.x,M.y,m.z),(m.x,M.y,M.z),
+ (M.x,m.y,m.z),(M.x,m.y,M.z),(M.x,M.y,m.z),M};
+ return max(abs(c-target));
+ }
+
+
+ // This is redefined here to make projection as self-contained as possible.
+ static private real sqrtEpsilon = sqrt(realEpsilon);
+
+ // Move the camera so that the box(m,M) rotated about target will always
+ // lie in front of the clipping plane.
+ bool adjust(triple m, triple M) {
+ triple v=camera-target;
+ real d=distance(m,M);
+ static real lambda=camerafactor*(1-sqrtEpsilon);
+ if(lambda*d >= abs(v)) {
+ camera=target+camerafactor*d*unit(v);
+ calculate();
+ return true;
+ }
+ return false;
+ }
+}
+
+projection currentprojection;
+
+struct light {
+ real[][] diffuse;
+ real[][] ambient;
+ real[][] specular;
+ pen background=nullpen; // 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 currently implemented.
+
+ transform3 T=identity(4); // Transform to apply to normal vectors.
+
+ bool on() {return position.length > 0;}
+
+ void operator init(pen[] diffuse,
+ pen[] ambient=array(diffuse.length,black),
+ pen[] specular=diffuse, pen background=nullpen,
+ real specularfactor=1,
+ bool viewport=false, 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.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=false...triple[] position) {
+ int n=position.length;
+ operator init(array(n,diffuse),array(n,ambient),array(n,specular),
+ background,specularfactor,viewport,position);
+ }
+
+ void operator init(pen diffuse=white, pen ambient=black, pen specular=diffuse,
+ pen background=nullpen, bool viewport=false,
+ real x, real y, real z) {
+ operator init(diffuse,ambient,specular,background,viewport,(x,y,z));
+ }
+
+ void operator init(explicit light light) {
+ diffuse=copy(light.diffuse);
+ ambient=copy(light.ambient);
+ specular=copy(light.specular);
+ background=light.background;
+ specularfactor=light.specularfactor;
+ viewport=light.viewport;
+ position=copy(light.position);
+ }
+
+ real[] background() {return rgba(background == nullpen ? white : background);}
+}
+
+light currentlight;
+
diff --git a/Build/source/utils/asymptote/base/plain_scaling.asy b/Build/source/utils/asymptote/base/plain_scaling.asy
new file mode 100644
index 00000000000..fd2dbae07c0
--- /dev/null
+++ b/Build/source/utils/asymptote/base/plain_scaling.asy
@@ -0,0 +1,246 @@
+real expansionfactor=sqrt(2);
+
+// A coordinate in "flex space." A linear combination of user and true-size
+// coordinates.
+struct coord {
+ real user,truesize;
+
+ // Build a coord.
+ static coord build(real user, real truesize) {
+ coord c=new coord;
+ c.user=user;
+ c.truesize=truesize;
+ return c;
+ }
+
+ // Deep copy of coordinate. Users may add coords to the picture, but then
+ // modify the struct. To prevent this from yielding unexpected results, deep
+ // copying is used.
+ coord copy() {
+ return build(user, truesize);
+ }
+
+ void clip(real min, real max) {
+ user=min(max(user,min),max);
+ truesize=0;
+ }
+}
+
+bool operator <= (coord a, coord b)
+{
+ return a.user <= b.user && a.truesize <= b.truesize;
+}
+
+bool operator >= (coord a, coord b)
+{
+ return a.user >= b.user && a.truesize >= b.truesize;
+}
+
+// Find the maximal elements of the input array, using the partial ordering
+// given.
+coord[] maxcoords(coord[] in, bool operator <= (coord,coord))
+{
+ // As operator <= is defined in the parameter list, it has a special
+ // meaning in the body of the function.
+
+ coord best;
+ coord[] c;
+
+ int n=in.length;
+
+ if(n == 0)
+ return c;
+
+ int first=0;
+ // Add the first coord without checking restrictions (as there are none).
+ best=in[first];
+ c.push(best);
+
+ static int NONE=-1;
+
+ int dominator(coord x)
+ {
+ // This assumes it has already been checked against the best.
+ for(int i=1; i < c.length; ++i)
+ if(x <= c[i])
+ return i;
+ return NONE;
+ }
+
+ void promote(int i)
+ {
+ // Swap with the top
+ coord x=c[i];
+ c[i]=best;
+ best=c[0]=x;
+ }
+
+ void addmaximal(coord x)
+ {
+ coord[] newc;
+
+ // Check if it beats any others.
+ for(int i=0; i < c.length; ++i) {
+ coord y=c[i];
+ if(!(y <= x))
+ newc.push(y);
+ }
+ newc.push(x);
+ c=newc;
+ best=c[0];
+ }
+
+ void add(coord x)
+ {
+ if(x <= best)
+ return;
+ else {
+ int i=dominator(x);
+ if(i == NONE)
+ addmaximal(x);
+ else
+ promote(i);
+ }
+ }
+
+ for(int i=1; i < n; ++i)
+ add(in[i]);
+
+ return c;
+}
+
+struct coords2 {
+ coord[] x,y;
+ void erase() {
+ x.delete();
+ y.delete();
+ }
+ // Only a shallow copy of the individual elements of x and y
+ // is needed since, once entered, they are never modified.
+ coords2 copy() {
+ coords2 c=new coords2;
+ c.x=copy(x);
+ c.y=copy(y);
+ return c;
+ }
+ void append(coords2 c) {
+ x.append(c.x);
+ y.append(c.y);
+ }
+ void push(pair user, pair truesize) {
+ x.push(coord.build(user.x,truesize.x));
+ y.push(coord.build(user.y,truesize.y));
+ }
+ void push(coord cx, coord cy) {
+ x.push(cx);
+ y.push(cy);
+ }
+ void push(transform t, coords2 c1, coords2 c2) {
+ for(int i=0; i < c1.x.length; ++i) {
+ coord cx=c1.x[i], cy=c2.y[i];
+ pair tinf=shiftless(t)*(0,0);
+ pair z=t*(cx.user,cy.user);
+ pair w=(cx.truesize,cy.truesize);
+ w=length(w)*unit(shiftless(t)*w);
+ coord Cx,Cy;
+ Cx.user=z.x;
+ Cy.user=z.y;
+ Cx.truesize=w.x;
+ Cy.truesize=w.y;
+ push(Cx,Cy);
+ }
+ }
+ void xclip(real min, real max) {
+ for(int i=0; i < x.length; ++i)
+ x[i].clip(min,max);
+ }
+ void yclip(real min, real max) {
+ for(int i=0; i < y.length; ++i)
+ y[i].clip(min,max);
+ }
+}
+
+// The scaling in one dimension: x --> a*x + b
+struct scaling {
+ real a,b;
+ static scaling build(real a, real b) {
+ scaling s=new scaling;
+ s.a=a; s.b=b;
+ return s;
+ }
+ real scale(real x) {
+ return a*x+b;
+ }
+ real scale(coord c) {
+ return scale(c.user) + c.truesize;
+ }
+}
+
+// Calculate the minimum point in scaling the coords.
+real min(real m, scaling s, coord[] c) {
+ for(int i=0; i < c.length; ++i)
+ if(s.scale(c[i]) < m)
+ m=s.scale(c[i]);
+ return m;
+}
+
+// Calculate the maximum point in scaling the coords.
+real max(real M, scaling s, coord[] c) {
+ for(int i=0; i < c.length; ++i)
+ if(s.scale(c[i]) > M)
+ M=s.scale(c[i]);
+ return M;
+}
+
+// Calculate the sizing constants for the given array and maximum size.
+real calculateScaling(string dir, coord[] m, coord[] M, real size,
+ bool warn=true) {
+ access simplex;
+ simplex.problem p=new simplex.problem;
+
+ void addMinCoord(coord c) {
+ // (a*user + b) + truesize >= 0:
+ p.addRestriction(c.user,1,c.truesize);
+ }
+ void addMaxCoord(coord c) {
+ // (a*user + b) + truesize <= size:
+ p.addRestriction(-c.user,-1,size-c.truesize);
+ }
+
+ for (int i=0; i < m.length; ++i)
+ addMinCoord(m[i]);
+ for (int i=0; i < M.length; ++i)
+ addMaxCoord(M[i]);
+
+ int status=p.optimize();
+ if(status == simplex.problem.OPTIMAL) {
+ // TODO: Could just be return a;
+ return scaling.build(p.a(),p.b()).a;
+ } else if(status == simplex.problem.UNBOUNDED) {
+ if(warn) warning("unbounded",dir+" scaling in picture unbounded");
+ return 0;
+ } else {
+ if(!warn) return 1;
+
+ bool userzero(coord[] coords) {
+ for(var coord : coords)
+ if(coord.user != 0) return false;
+ return true;
+ }
+
+ if((userzero(m) && userzero(M)) || size >= infinity) return 1;
+
+ warning("cannotfit","cannot fit picture to "+dir+"size "+(string) size
+ +"...enlarging...");
+
+ return calculateScaling(dir,m,M,expansionfactor*size,warn);
+ }
+}
+
+real calculateScaling(string dir, coord[] coords, real size, bool warn=true)
+{
+ coord[] m=maxcoords(coords,operator >=);
+ coord[] M=maxcoords(coords,operator <=);
+
+ return calculateScaling(dir, m, M, size, warn);
+}
diff --git a/Build/source/utils/asymptote/base/plain_shipout.asy b/Build/source/utils/asymptote/base/plain_shipout.asy
index e96a3a8acb1..ccf94e6c9fd 100644
--- a/Build/source/utils/asymptote/base/plain_shipout.asy
+++ b/Build/source/utils/asymptote/base/plain_shipout.asy
@@ -1,6 +1,8 @@
// Default file prefix used for inline LaTeX mode
string defaultfilename;
+string[] file3;
+
string outprefix(string prefix=defaultfilename) {
return stripextension(prefix != "" ? prefix : outname());
}
@@ -77,7 +79,8 @@ void shipout(string prefix=defaultfilename, frame f,
int limit=2000;
if(abs(m.x) > limit || abs(m.y) > limit) f=shift(-m)*f;
- shipout(prefix,f,currentpatterns,format,wait,view,xformStack.pop0);
+ shipout(prefix,f,currentpatterns,format,wait,view,
+ xformStack.empty() ? null : xformStack.pop0);
shipped=true;
}
@@ -91,8 +94,17 @@ void shipout(string prefix=defaultfilename, picture pic=currentpicture,
bool inlinetex=settings.inlinetex;
bool prc=prc(format);
bool empty3=pic.empty3();
- if(prc && !empty3)
+ if(prc && !empty3) {
+ if(settings.render == 0) {
+ string image=outprefix(prefix)+"+"+(string) file3.length;
+ if(settings.inlineimage) image += "_0";
+ settings.inlinetex=false;
+ settings.prc=false;
+ shipout(image,pic,orientation,nativeformat(),view=false,light,P);
+ settings.prc=true;
+ }
settings.inlinetex=settings.inlineimage;
+ }
frame f=pic.fit(prefix,format,view=view,options,script,light,P);
if(!pic.empty2() || settings.render == 0 || prc || empty3)
shipout(prefix,orientation(f),format,wait,view);
diff --git a/Build/source/utils/asymptote/base/plain_strings.asy b/Build/source/utils/asymptote/base/plain_strings.asy
index 138ab05ca05..98f72f460aa 100644
--- a/Build/source/utils/asymptote/base/plain_strings.asy
+++ b/Build/source/utils/asymptote/base/plain_strings.asy
@@ -155,16 +155,24 @@ private void notimplemented(string text)
abort(text+" is not implemented for the '"+settings.tex+"' TeX engine");
}
+string jobname(string name)
+{
+ int pos=rfind(name,"-");
+ return pos >= 0 ? "\ASYprefix\jobname"+substr(name,pos) : name;
+}
+
string graphic(string name, string options="")
{
if(latex()) {
if(options != "") options="["+options+"]";
- if(find(name," ") < 0)
- return "\includegraphics"+options+"{"+name+"}";
- else {
- return "\includegraphics"+options+
- (pdf() ? "{\""+stripextension(name)+"\".pdf}" : "{\""+name+"\"}");
- }
+ bool pdf=pdf();
+ string includegraphics="\includegraphics"+options;
+ if(settings.inlinetex)
+ return includegraphics+"{"+jobname(name)+"}";
+ else
+ return includegraphics+
+ (find(name," ") < 0 ? "{"+name+"}" :
+ (pdf ? "{\""+stripextension(name)+"\".pdf}" : "{\""+name+"\"}"));
}
if(settings.tex != "context")
notimplemented("graphic");
diff --git a/Build/source/utils/asymptote/base/plain_xasy.asy b/Build/source/utils/asymptote/base/plain_xasy.asy
index 162cbfb35ad..efc739d8385 100644
--- a/Build/source/utils/asymptote/base/plain_xasy.asy
+++ b/Build/source/utils/asymptote/base/plain_xasy.asy
@@ -113,11 +113,15 @@ struct framedTransformStack {
toPush[tList[a].index]=transact(tList[a]);
for(int a=0; a < toPush.length; ++a)
if(!toPush.initialized(a))
- toPush[a]=transact();
+ toPush[a]=transact();
report("Added");
report(toPush.length);
stack.append(toPush);
}
+
+ bool empty() {
+ return stack.length == 0;
+ }
}
framedTransformStack xformStack;
diff --git a/Build/source/utils/asymptote/base/simplex.asy b/Build/source/utils/asymptote/base/simplex.asy
index bd9f69c9324..43920109ff4 100644
--- a/Build/source/utils/asymptote/base/simplex.asy
+++ b/Build/source/utils/asymptote/base/simplex.asy
@@ -184,8 +184,10 @@ struct problem {
// Checks that constants are valid.
bool validConstants() {
for (int i = 0; i < rows.length; ++i)
- if (rows[i].c < 0)
- return false;
+ // Do not test the row for b, as it does not have a non-negativity
+ // condition.
+ if (i != VAR_B && rows[i].c < 0)
+ return false;
return true;
}
diff --git a/Build/source/utils/asymptote/base/slide.asy b/Build/source/utils/asymptote/base/slide.asy
index 092c3429145..0a3e0f65fab 100644
--- a/Build/source/utils/asymptote/base/slide.asy
+++ b/Build/source/utils/asymptote/base/slide.asy
@@ -401,27 +401,27 @@ void figure(string[] s, string options="", real margin=0,
S[i]=graphic(s[i],options);
}
- display(S,margin,captions,caption,align,itempen,figuremattpen, final);
+ display(S,margin,captions,caption,align,itempen,figuremattpen,final);
}
void figure(string s, string options="", string caption="", pair align=S,
pen p=itempen, pen figuremattpen=figuremattpen, bool final=true)
{
- figure(new string[] {s},options,caption,align,p,figuremattpen, final);
+ figure(new string[] {s},options,caption,align,p,figuremattpen,final);
}
void multifigure(string[] slist, string options="", string caption="",
- pair align=S, pen p=itempen, pen figuremattpen=figuremattpen)
+ pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
+ bool step=itemstep)
{
- if (stepping) {
- int lastnode = currentpicture.nodes.length-1;
+ if(step) {
+ int lastnode=currentpicture.nodes.length-1;
for (int i=0; i<slist.length-1; ++i) {
- figure(slist[i], options, caption, align, p, figuremattpen, final=false);
+ figure(slist[i],options,caption,align,p,figuremattpen,final=false);
erasestep(lastnode);
}
}
- figure(slist[slist.length-1], options, caption, align, p, figuremattpen,
- final=true);
+ figure(slist[slist.length-1],options,caption,align,p,figuremattpen,final=true);
if(!firststep) step();
firststep=false;
@@ -429,12 +429,13 @@ void multifigure(string[] slist, string options="", string caption="",
void indexedfigure(string prefix, int first, int last,
string options="", string caption="",
- pair align=S, pen p=itempen, pen figuremattpen=figuremattpen)
+ pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
+ bool step=itemstep)
{
string[] s;
for(int i=first; i <= last; ++i)
s.push(prefix+string(i));
- multifigure(s, options, caption, align, p, figuremattpen);
+ multifigure(s,options,caption,align,p,figuremattpen,step=step);
}
string[] codefile;
diff --git a/Build/source/utils/asymptote/base/solids.asy b/Build/source/utils/asymptote/base/solids.asy
index c9be44552c9..239bce4b9a0 100644
--- a/Build/source/utils/asymptote/base/solids.asy
+++ b/Build/source/utils/asymptote/base/solids.asy
@@ -1,4 +1,3 @@
-import three;
import graph3;
pen defaultbackpen=linetype(new real[] {4,4},4,scale=false);
diff --git a/Build/source/utils/asymptote/base/three.asy b/Build/source/utils/asymptote/base/three.asy
index 4221646f632..033461263eb 100644
--- a/Build/source/utils/asymptote/base/three.asy
+++ b/Build/source/utils/asymptote/base/three.asy
@@ -28,9 +28,11 @@ struct render
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)
+
+ bool3 merge; // merge nodes before rendering, for faster but
+ // lower quality PRC rendering (the value default means
+ // merge opaque patches only).
+
int sphere; // PRC sphere type (PRCsphere or NURBSsphere).
// General parameters:
@@ -2408,7 +2410,8 @@ triple point(frame f, triple dir)
triple point(picture pic=currentpicture, triple dir, bool user=true,
projection P=currentprojection)
{
- triple v=pic.userMin+realmult(rectify(dir),pic.userMax-pic.userMin);
+ triple min = pic.userMin(), max = pic.userMax();
+ triple v=min+realmult(rectify(dir),max-min);
return user ? v : pic.calculateTransform3(P)*v;
}
@@ -2509,8 +2512,6 @@ private string format(triple v, string sep=" ")
return string(v.x)+sep+string(v.y)+sep+string(v.z);
}
-private string[] file3;
-
private string projection(bool infinity, real viewplanesize)
{
return "activeCamera=scene.cameras.getByIndex(0);
@@ -2696,9 +2697,8 @@ string embed3D(string label="", string text=label, string prefix,
writeJavaScript(name,lightscript+projection(P.infinity,viewplanesize)+
billboard(index,center),script);
- prefix += ".prc";
if(!settings.inlinetex)
- file3.push(prefix);
+ file3.push(prefix+".prc");
triple target=P.target;
if(P.viewportshift != 0) {
@@ -2730,9 +2730,11 @@ string embed3D(string label="", string text=label, string prefix,
",3Droo="+Format(abs(v))+
",3Dbg="+Format(light.background());
if(options != "") options3 += ","+options;
- if(name != "") options3 += ",3Djscript="+stripdirectory(name);
+ if(settings.inlinetex)
+ prefix=jobname(prefix);
+ options3 += ",3Djscript="+prefix+".js";
- return Embed(stripdirectory(prefix),options3,width,height);
+ return Embed(prefix+".prc",options3,width,height);
}
struct scene
@@ -2983,7 +2985,7 @@ object embed(string label="", string text=label, string prefix=defaultfilename,
}
string image;
- if(preview && settings.embed) {
+ if((preview || (prc && settings.render == 0)) && settings.embed) {
image=prefix;
if(settings.inlinetex) image += "_0";
image += "."+nativeformat();
diff --git a/Build/source/utils/asymptote/base/three_surface.asy b/Build/source/utils/asymptote/base/three_surface.asy
index 8e48b0606a3..88e42cf6640 100644
--- a/Build/source/utils/asymptote/base/three_surface.asy
+++ b/Build/source/utils/asymptote/base/three_surface.asy
@@ -1435,7 +1435,8 @@ void label(frame f, Label L, triple position, align align=NoAlign,
bool lighton=light.on();
for(patch S : surface(L,position,bbox=P.bboxonly).s) {
draw3D(f,S,position,L.p,light,interaction);
- if(render.labelfill && !lighton) // Fill subdivision cracks
+ // Fill subdivision cracks
+ if(render.labelfill && opacity(L.p) == 1 && !lighton)
_draw(f,S.external(),position,L.p,interaction.type);
}
} else {
@@ -1485,7 +1486,8 @@ void label(picture pic=currentpicture, Label L, triple position,
if(is3D()) {
for(patch S : surface(L,v,bbox=P.bboxonly).s) {
draw3D(f,S,v,L.p,light,interaction);
- if(render.labelfill && !lighton) // Fill subdivision cracks
+ // Fill subdivision cracks
+ if(render.labelfill && opacity(L.p) == 1 && !lighton)
_draw(f,S.external(),v,L.p,interaction.type);
}
}
@@ -1819,6 +1821,26 @@ void dot(picture pic=currentpicture, Label L, triple v, align align=NoAlign,
label(pic,L,v,render);
}
+void pixel(picture pic=currentpicture, triple v, pen p=currentpen,
+ real width=1)
+{
+ real h=0.5*width;
+ pic.add(new void(frame f, transform3 t, picture pic, projection P) {
+ triple V=t*v;
+ if(is3D())
+ drawpixel(f,V,p,width);
+ if(pic != null) {
+ triple R=h*unit(cross(unit(P.vector()),P.up));
+ pair z=project(V,P.t);
+ real h=0.5*abs(project(V+R,P.t)-project(V-R,P.t));
+ pair r=h*(1,1)/mm;
+ fill(pic,box(z-r,z+r),p,false);
+ }
+ },true);
+ triple R=h*(1,1,1);
+ pic.addBox(v,v,-R,R);
+}
+
pair minbound(triple[] A, projection P)
{
pair b=project(A[0],P);
diff --git a/Build/source/utils/asymptote/base/trembling.asy b/Build/source/utils/asymptote/base/trembling.asy
index 61e78a4fca3..6f6f5973332 100644
--- a/Build/source/utils/asymptote/base/trembling.asy
+++ b/Build/source/utils/asymptote/base/trembling.asy
@@ -1,246 +1,209 @@
-// Copyright (c) 2008, Philippe Ivaldi.
-// http://www.piprime.fr/
+// Copyright(c) 2008, Philippe Ivaldi.
+// Simplified by John Bowman 02Feb2011
+// http: //www.piprime.fr/
// trembling.asy: handwriting package for the software Asymptote.
-// This program is free software ; you can redistribute it and/or modify
+// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
-// the Free Software Foundation ; either version 3 of the License, or
-// (at your option) any later version.
+// the Free Software Foundation; either version 3 of the License, or
+//(at your option) any later version.
// This program is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY ; without even the implied warranty of
+// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
// You should have received a copy of the GNU Lesser General Public License
-// along with this program ; if not, write to the Free Software
+// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-// COMMENTARY:
+// COMMENTARY:
-// THANKS:
+// THANKS:
-// BUGS:
+// BUGS:
// magnetic points are experimental...
-// CODE:
+// CODE:
-import geometry;
-import stats;
-
-/*<asyxml><variable type="pair[]" signature="magneticPoints"><code></asyxml>*/
-pair[] magneticPoints;
-/*<asyxml></code><documentation>Array of magnetic points.
- When a point is magnetized, a trembled path will pass though P if the original path passes through P.
- When trembling is enabled with the routine 'startTrembling' all the drawn points is added to this array.
- For convenience, one can magnetize an arbitrary number of points with the routine 'magnetize'.<look href="#magnetize(...point[])"><look href="#startTrembling(real,real,real,real,bool">
- </documentation></variable></asyxml>*/
real magneticRadius=1; // unit is bp in postscript coordinates.
real trembleFuzz(){return min(1e-3,magneticRadius/10);}
-// real trembleFuzz(){return min(1e-1,1);}
-pair[] single(pair[] P)
+/* <asyxml> <variable type="real" signature="trembleAngle"> <code> </asyxml> */
+real trembleAngle=4, trembleFrequency=0.5, trembleRandom=2;
+/* <asyxml> </code> <documentation> Variables used by the routine 'tremble'.
+ </documentation> </variable> </asyxml> */
+
+struct tremble
{
- pair[] op;
- bool allow;
- for (int i=0; i < P.length-1; ++i) {
- allow=true;
- for (int j=i+1; j < P.length; ++j) {
- if(abs(P[i]-P[j]) < magneticRadius) {
- allow=false;
- break;
+ static real test=5;
+
+ real angle,frequency,random,fuzz;
+
+ pair[] single(pair[] P)
+ {
+ pair[] op;
+ bool allow;
+ for(int i=0; i < P.length-1; ++i) {
+ allow=true;
+ for(int j=i+1; j < P.length; ++j) {
+ if(abs(P[i]-P[j]) < magneticRadius) {
+ allow=false;
+ break;
+ }
}
+ if(allow) op.push(P[i]);
}
- if(allow) op.push(P[i]);
+ if(P.length > 0) op.push(P[P.length-1]);
+ return op;
}
- if(P.length > 0) op.push(P[P.length-1]);
- return op;
-}
-/*<asyxml><function type="pair" signature="attract(pair,path,real)"><code></asyxml>*/
-real atime(pair m, path g, real fuzz=trembleFuzz())
-{/*<asyxml></code><documentation>Return the time of the nearest point of 'm' which is on the path g.
- 'fuzz' is the argument 'fuzz' of 'intersect'.</documentation></function></asyxml>*/
- if(length(g) == 0) return 0.0;
- real[] t=intersect(m,g,fuzz);
- if(t.length > 0) return t[1];
- real ot;
- static real eps=sqrt(realEpsilon);
- real abmax=abs(max(g)-m), abmin=abs(min(g)-m);
- real initr=abs(m-midpoint(g));
- real maxR=2*max(abmax,abmin), step=eps, r=initr;
- real shx=1e-4;
- transform T=shift(m);
- path ig;
- // do {
- // do {// Find a radius for intersection
- // r += step;
- // ig=T*scale(r)*unitcircle;
- // if(ig == g) {
- // T *= shift(shx,0);
- // ig=T*scale(r)*unitcircle;
- // }
- // t=intersect(ig,g);
- // } while(t.length <= 0 && r <= maxR && inside(g,ig) != 1);//
- // if(t.length <= 0) { // degenerated case
- // r=initr;
- // T *= shift(shx,0);
- // warning("atime","atime needs numerical adjustment.",position=true);
- // }
- // } while(t.length <= 0);
- if(t.length > 0) ot=t[1];
- real rm=0, rM=r;
- while(rM-rm > eps) {
- r=(rm+rM)/2;
- t=intersect(T*scale(r)*unitcircle,g,fuzz);
- if(t.length <= 0) {
- rm=r;
- } else {
- rM=r;
- ot=t[1];
+ /* <asyxml> <function type="pair" signature="attract(pair,path,real)"> <code>
+ </asyxml> */
+ real atime(pair m, path g, real fuzz=trembleFuzz())
+ {/* <asyxml> </code> <documentation> Return the time of the point on path g
+ nearest to 'm'.
+ 'fuzz' is the argument 'fuzz' of 'intersect'. </documentation> </function>
+ </asyxml> */
+ if(length(g) == 0) return 0.0;
+ real[] t=intersect(m,g,fuzz);
+ if(t.length > 0) return t[1];
+ real ot;
+ static real eps=sqrt(realEpsilon);
+ real abmax=abs(max(g)-m), abmin=abs(min(g)-m);
+ real initr=abs(m-midpoint(g));
+ real maxR=2*max(abmax,abmin), step=eps, r=initr;
+ real shx=1e-4;
+ transform T=shift(m);
+ path ig;
+ if(t.length > 0) ot=t[1];
+ real rm=0, rM=r;
+ while(rM-rm > eps) {
+ r=(rm+rM)/2;
+ t=intersect(T*scale(r)*unitcircle,g,fuzz);
+ if(t.length <= 0) {
+ rm=r;
+ } else {
+ rM=r;
+ ot=t[1];
+ }
}
+ return ot;
}
- return ot;
-}
-
-/*<asyxml><function type="void" signature="magnetize(...pair[])"><code></asyxml>*/
-void magnetize(...pair[] P)
-{/*<asyxml></code><documentation>Magnetize the points P.
- When a point is magnetized, a trembled path will pass though P if the original path passes through P.</documentation></function></asyxml>*/
- if(magneticRadius <= 0) return;
- currentpicture.uptodate=false;
- currentpicture.nodes.insert(0,
- new void(frame f, transform t, transform T, pair lb, pair rt)
- {
- for (pair PT:P) {
- magneticPoints.push(t*PT);
- }
- });
-}
-/*<asyxml><function type="void" signature="magnetize(...triangle[])"><code></asyxml>*/
-void magnetize(...triangle[] t)
-{/*<asyxml></code><documentation>Magnetize the vertices of the triangles t.<look href="#magnetize(...pair[])"/></documentation></function></asyxml>*/
- for(int i=0; i < t.length; ++i)
- magnetize(...new point[] {t[i].A, t[i].B, t[i].C});
-}
-
-void trueMagnetize(pair p)
-{
- if(magneticRadius <= 0) return;
- magneticPoints.push(p);
-}
-
-/*<asyxml><function type="path" signature="addnode(path,real)"><code></asyxml>*/
-path addnode(path g, real t)
-{/*<asyxml></code><documentation>Add a node to 'g' at point(g,t).</documentation></function></asyxml>*/
- real l=length(g);
- real rt=t%1;
- if (l==0 || (t > l && !cyclic(g)) || rt == 0) return g;
- if(cyclic(g)) t=t%l;
- int t0=floor(t);
- int t1=t0+1;
- pair z0=point(g,t0), z1=point(g,t1),
- c0=postcontrol(g,t0), c1=precontrol(g,t1),
- m0=(1-rt)*z0+rt*c0, m1=(1-rt)*c0+rt*c1,
- m2=(1-rt)*c1+rt*z1, m3=(1-rt)*m0+rt*m1,
- m4=(1-rt)*m1+rt*m2;
- guide og=subpath(g,0,t0);
- og=og..controls m0 and m3..point(g,t);
- if(cyclic(g))
- if(t1 < l) {
- og=og..controls m4 and m2..subpath(g,t1,l)&cycle;
- } else og=og..controls m4 and m2..cycle;
- else og=og..controls m4 and m2..subpath(g,t1,l);
- return og;
-}
-
-path addnodes(path g, real fuzz=trembleFuzz() ...pair[] P)
-{
- pair[] P=single(P);
- if(length(g) == 0 || P.length == 0 || magneticRadius <= 0) return g;
- path og=g;
- for(pair tp:P) {
- real t=atime(tp,og,fuzz);
- real d=abs(tp-point(og,t));
- if(d < magneticRadius) og=addnode(og,t);
+ /* <asyxml> <function type="path" signature="addnode(path,real)"> <code>
+ </asyxml> */
+ path addnode(path g, real t)
+ {/* <asyxml> </code> <documentation> Add a node to 'g' at point(g,t).
+ </documentation> </function> </asyxml> */
+ real l=length(g);
+ real rt=t % 1;
+ if(l == 0 || (t > l && !cyclic(g)) || rt == 0) return g;
+ if(cyclic(g)) t=t % l;
+ int t0=floor(t);
+ int t1=t0+1;
+ pair z0=point(g,t0), z1=point(g,t1),
+ c0=postcontrol(g,t0), c1=precontrol(g,t1),
+ m0=(1-rt)*z0+rt*c0, m1=(1-rt)*c0+rt*c1,
+ m2=(1-rt)*c1+rt*z1, m3=(1-rt)*m0+rt*m1,
+ m4=(1-rt)*m1+rt*m2;
+ guide og=subpath(g,0,t0)..controls m0 and m3..point(g,t);
+ if(cyclic(g)) {
+ if(t1 < l)
+ og=og..controls m4 and m2..subpath(g,t1,l)&cycle;
+ else og=og..controls m4 and m2..cycle;
+ } else og=og..controls m4 and m2..subpath(g,t1,l);
+ return og;
}
- return og;
-}
-/*<asyxml><function type="path" signature="addnodes(path,int)"><code></asyxml>*/
-path addnodes(path g, int n)
-{/*<asyxml></code><documentation>Add 'n' nodes between each node of 'g'.</documentation></function></asyxml>*/
- real l=length(g);
- if(n == 0 || l == 0) return g;
- path og=g;
- int np=0;
- for (int i=0; i < l; ++i) {
- real step=1/(n+1);
- for (int j=0; j < n; ++j) {
- og=addnode(og,i*(n+1)+j+step);
- step=1/(n-j);
+ path addnodes(path g, real fuzz=trembleFuzz()...pair[] P)
+ {
+ pair[] P=single(P);
+ if(length(g) == 0 || P.length == 0 || magneticRadius <= 0) return g;
+ path og=g;
+ for(pair tp: P) {
+ real t=atime(tp,og,fuzz);
+ real d=abs(tp-point(og,t));
+ if(d < magneticRadius) og=addnode(og,t);
}
+ return og;
}
- return og;
-}
-
-
-/*<asyxml><variable type="real" signature="trembleAngle"><code></asyxml>*/
-real trembleAngle=4, trembleFrequency=0.5, trembleRandom=2;/*<asyxml></code><documentation>Variables used by the routine 'tremble'.</documentation></variable></asyxml>*/
-
-/*<asyxml><function type="path" signature="tremble(path,real,real,real,real)"><code></asyxml>*/
-path tremble(path g,
- real angle=trembleAngle,
- real frequency=trembleFrequency,
- real random=trembleRandom,
- real fuzz=trembleFuzz())
-{/*<asyxml></code><documentation>Return g as it was handwriting.
- The postcontrols and precontrols of the nodes of g will be rotated
- by an angle proportional to 'angle' (in degrees).
- If frequency < 1, floor(1/frequency) nodes will be added to g to increase the
- control points.
- If frequency >= 1, one point for floor(frequency) will be used to deform the path.
- 'random' controls the randomized coefficient which will be multiplied 'angle'.
- random is 0 means don't use randomized coefficient;
- More 'random' is hight more the coefficient is hight and the trembling seems randomized.</documentation></function></asyxml>*/
- if(length(g) == 0) return g;
- path tg=g;
- frequency=abs(frequency);
- int f=abs(floor(1/frequency)-1);
- tg=addnodes(tg,f);
- int frequency=floor(frequency);
- int tf=(frequency == 0) ? 1 : frequency;
- int l=length(tg);
- guide og=point(tg,0);
- random=abs(random);
- int rsgn(real x){
- int d2=floor(100*x)-10*floor(10*x);
- if(d2 == 0) return 1;
- return 2%d2 == 0 ? 1 : -1;
- }
- real randf()
- {
- real or;
- if(random != 0)
- if(1%tf != 0) or=0; else {
- real ur=unitrand();
- or=rsgn(ur)*angle*(1+ur^(1/random));
+ /* <asyxml> <function type="path" signature="addnodes(path,int)"> <code>
+ </asyxml> */
+ path addnodes(path g, int n)
+ {/* <asyxml> </code> <documentation> Add 'n' nodes between each node of 'g'.
+ </documentation> </function> </asyxml> */
+ real l=length(g);
+ if(n == 0 || l == 0) return g;
+ path og=g;
+ int np=0;
+ for(int i=0; i < l; ++i) {
+ real step=1/(n+1);
+ for(int j=0; j < n; ++j) {
+ og=addnode(og,i*(n+1)+j+step);
+ step=1/(n-j);
}
- else or=rsgn(unitrand())*1.5*angle;
- return or;
+ }
+ return og;
}
- real first=randf(), a=first;
- real gle;
- for(int i=1; i <= l; ++i)
+ /* <asyxml> <function type="path"
+ signature="tremble(path,real,real,real,real,pair[] )"> <code> </asyxml> */
+ void operator init(real angle=trembleAngle, real frequency=trembleFrequency,
+ real random=trembleRandom, real fuzz=trembleFuzz()) {
+ this.angle=angle;
+ this.frequency=frequency;
+ this.random=random;
+ this.fuzz=fuzz;
+ }
+
+ path deform(path g...pair[] magneticPoints) {
+ /* <asyxml> </code> <documentation> Return g as it was handwriting.
+ The postcontrols and precontrols of the nodes of g will be rotated
+ by an angle proportional to 'angle'(in degrees).
+ If frequency < 1, floor(1/frequency) nodes will be added to g to
+ increase the control points.
+ If frequency>= 1, one point for floor(frequency) will be used to deform
+ the path.
+ 'random' controls the randomized coefficient which will be multiplied
+ by 'angle'.
+ random is 0 means don't use randomized coefficient;
+ The higher 'random' is, the more the trembling is randomized.
+ </documentation> </function> </asyxml> */
+ if(length(g) == 0) return g;
+ g=addnodes(g,fuzz*abs(max(g)-min(g))...magneticPoints);
+ path tg=g;
+ frequency=abs(frequency);
+ int f=abs(floor(1/frequency)-1);
+ tg=addnodes(tg,f);
+ int frequency=floor(frequency);
+ int tf=(frequency == 0) ? 1 : frequency;
+ int l=length(tg);
+ guide og=point(tg,0);
+ random=abs(random);
+ int rsgn(real x){
+ int d2=floor(100*x)-10*floor(10*x);
+ if(d2 == 0) return 1;
+ return 2 % d2 == 0 ? 1 : -1;
+ }
+ real randf()
{
+ real or;
+ if(random != 0) {
+ if(1 % tf != 0) or=0;
+ else {
+ real ur=unitrand();
+ or=rsgn(ur)*angle*(1+ur^(1/random));
+ }
+ } else or=rsgn(unitrand())*1.5*angle;
+ return or;
+ }
+
+ real first=randf();
+ for(int i=1; i <= l; ++i) {
pair P=point(tg,i);
- // gle=(i == l && (cyclic(tg))) ? first : a;
- // pair post=rotate(gle,point(tg,i-1))*postcontrol(tg,i-1);
- // pair pre=rotate(gle,P)*precontrol(tg,i);
- a=randf();
+ real a=randf();
pair post=rotate(a,point(tg,i-1))*postcontrol(tg,i-1);
pair pre=rotate((a+randf())/2,P)*precontrol(tg,i);
if(i == l && (cyclic(tg)))
@@ -248,121 +211,6 @@ path tremble(path g,
else
og=og..controls post and pre..P;
}
- return og;
-}
-
-typedef path pathModifier(path);
-pathModifier NoModifier=new path(path g){return g;};
-pathModifier tremble(real angle=trembleAngle,
- real frequency=trembleFrequency,
- real random=trembleRandom,
- real fuzz=trembleFuzz())
-{
- return new path(path g){return tremble(g,angle,frequency,random,fuzz);};
-}
-
-void orig_draw(frame f, path g, pen p=currentpen)=draw;
-void tremble_draw(frame f, path g, pen p=currentpen){}
-
-void tremble_marknodes(picture pic=currentpicture, frame f, path g) {}
-void tremble_markuniform(bool centered=false, int n, bool rotated=false) {}
-
-int tremble_circlenodesnumber(real r){return 5;}
-int orig_circlenodesnumber(real r)=circlenodesnumber;
-
-int tremble_circlenodesnumber1(real r, real angle1, real angle2){return 4;}
-int orig_circlenodesnumber1(real r, real angle1, real angle2)=circlenodesnumber;
-
-int tremble_ellipsenodesnumber(real a, real b){return 50;}
-int orig_ellipsenodesnumber(real a, real b)=ellipsenodesnumber;
-
-int tremble_ellipsenodesnumber1(real a, real b, real angle1, real angle2, bool dir){return 20;}
-int orig_ellipsenodesnumber1(real a, real b, real angle1, real angle2, bool dir)=ellipsenodesnumber;
-
-int tremble_parabolanodesnumber(parabola p, real angle1, real angle2){return 20;}
-int orig_parabolanodesnumber(parabola p, real angle1, real angle2)=parabolanodesnumber;
-
-int tremble_hyperbolanodesnumber(hyperbola h, real angle1, real angle2){return 20;}
-int orig_hyperbolanodesnumber(hyperbola h, real angle1, real angle2)=hyperbolanodesnumber;
-
-restricted bool tremblingMode=false;
-/*<asyxml><function type="void" signature="startTrembling(real,real,real,real,bool"><code></asyxml>*/
-void startTrembling(real angle=trembleAngle,
- real frequency=trembleFrequency,
- real random=trembleRandom,
- real fuzz=trembleFuzz(),
- bool magnetizePoints=true)
-{/*<asyxml></code><documentation>Calling this routine all drawn paths will be trembled with the givens parameters.<look href="#tremble(path,real,real,real,real)"/>
- If 'magnetizePoints' is true, most dotted points are automatically magnetized.<look href="magnetize(...pair[])"/></documentation></function></asyxml>*/
- if(!tremblingMode) {
- tremblingMode=true;
- tremble_draw=new void(frame f, path g, pen p=currentpen)
- {
- if(length(g) == 0 && magnetizePoints) {
- trueMagnetize(point(g,0));
- }
- g=addnodes(g,fuzz*abs(max(g)-min(g)) ...magneticPoints);
- orig_draw(f,tremble(g,angle,frequency,random,fuzz),p);
- };
-
- plain.draw=tremble_draw;
-
- if(magnetizePoints) {
- marknodes=new void(picture pic=currentpicture, frame f, path g)
- {
- for(int i=0; i <= length(g); ++i) {
- add(pic,f,point(g,i));
- magnetize(point(g,i));
- }
- };
- dot=dot();
-
- markuniform=new markroutine(bool centered=false, int n, bool rotated=false)
- {
- return new void(picture pic=currentpicture, frame f, path g) {
- if(n <= 0) return;
- void add(real x) {
- real t=reltime(g,x);
- add(pic,rotated ? rotate(degrees(dir(g,t)))*f : f,point(g,t));
- magnetize(point(g,t));
- }
- if(centered) {
- real width=1/n;
- for(int i=0; i < n; ++i) add((i+0.5)*width);
- } else {
- if(n == 1) add(0.5);
- else {
- real width=1/(n-1);
- for(int i=0; i < n; ++i)
- add(i*width);
- }
- }
- };
- };
- }
-
- circlenodesnumber=tremble_circlenodesnumber;
- circlenodesnumber=tremble_circlenodesnumber1;
-
- ellipsenodesnumber=tremble_ellipsenodesnumber;
- ellipsenodesnumber=tremble_ellipsenodesnumber1;
-
- parabolanodesnumber=tremble_parabolanodesnumber;
- hyperbolanodesnumber=tremble_hyperbolanodesnumber;
+ return og;
}
}
-
-// void stopTrembling()
-// {
-// if(tremblingMode) {
-// tremblingMode=false;
-// plain.draw=orig_draw;
-// // draw=orig_draw1;
-// circlenodesnumber=orig_circlenodesnumber;
-// circlenodesnumber=orig_circlenodesnumber1;
-// ellipsenodesnumber=orig_ellipsenodesnumber;
-// ellipsenodesnumber=orig_ellipsenodesnumber1;
-// parabolanodesnumber=orig_parabolanodesnumber;
-// hyperbolanodesnumber=orig_hyperbolanodesnumber;
-// }
-// }