summaryrefslogtreecommitdiff
path: root/graphics/asymptote/base
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-12-28 03:01:00 +0000
committerNorbert Preining <norbert@preining.info>2021-12-28 03:01:00 +0000
commitecdf859b6ce481abfd530425dcf6f0f764bd0001 (patch)
tree13bc161dc046876ac6c92fce5f9f5034ba9aa573 /graphics/asymptote/base
parent790995b7e79697514364450bf9c04f1b8d500838 (diff)
CTAN sync 202112280300
Diffstat (limited to 'graphics/asymptote/base')
-rw-r--r--graphics/asymptote/base/asy-mode.el8
-rw-r--r--graphics/asymptote/base/graph.asy23
-rw-r--r--graphics/asymptote/base/math.asy24
-rw-r--r--graphics/asymptote/base/plain.asy8
-rw-r--r--graphics/asymptote/base/plain_boxes.asy10
-rw-r--r--graphics/asymptote/base/plain_constants.asy18
-rw-r--r--graphics/asymptote/base/plain_filldraw.asy12
-rw-r--r--graphics/asymptote/base/plain_margins.asy20
-rw-r--r--graphics/asymptote/base/plain_markers.asy34
-rw-r--r--graphics/asymptote/base/plain_paths.asy32
-rw-r--r--graphics/asymptote/base/plain_pens.asy23
-rw-r--r--graphics/asymptote/base/plain_picture.asy118
-rw-r--r--graphics/asymptote/base/plain_prethree.asy13
-rw-r--r--graphics/asymptote/base/plain_scaling.asy18
-rw-r--r--graphics/asymptote/base/plain_shipout.asy18
-rw-r--r--graphics/asymptote/base/plain_strings.asy18
-rw-r--r--graphics/asymptote/base/pstoedit.asy2
-rw-r--r--graphics/asymptote/base/rational.asy2
-rw-r--r--graphics/asymptote/base/roundedpath.asy30
-rw-r--r--graphics/asymptote/base/shaders/blend.glsl84
-rw-r--r--graphics/asymptote/base/shaders/count.glsl11
-rw-r--r--graphics/asymptote/base/shaders/count0.glsl11
-rw-r--r--graphics/asymptote/base/shaders/fragment.glsl179
-rw-r--r--graphics/asymptote/base/shaders/offset.glsl11
-rw-r--r--graphics/asymptote/base/shaders/partialsum.glsl54
-rw-r--r--graphics/asymptote/base/shaders/postsum.glsl30
-rw-r--r--graphics/asymptote/base/shaders/presum.glsl34
-rw-r--r--graphics/asymptote/base/shaders/screen.glsl5
-rw-r--r--graphics/asymptote/base/shaders/vertex.glsl15
-rw-r--r--graphics/asymptote/base/simplex.asy6
-rw-r--r--graphics/asymptote/base/slide.asy24
-rw-r--r--graphics/asymptote/base/slopefield.asy8
-rw-r--r--graphics/asymptote/base/smoothcontour3.asy38
-rw-r--r--graphics/asymptote/base/solids.asy24
-rw-r--r--graphics/asymptote/base/stats.asy2
-rw-r--r--graphics/asymptote/base/syzygy.asy8
-rw-r--r--graphics/asymptote/base/three.asy259
-rw-r--r--graphics/asymptote/base/three_arrows.asy24
-rw-r--r--graphics/asymptote/base/three_light.asy6
-rw-r--r--graphics/asymptote/base/three_margins.asy20
-rw-r--r--graphics/asymptote/base/three_surface.asy256
-rw-r--r--graphics/asymptote/base/three_tube.asy25
-rw-r--r--graphics/asymptote/base/trembling.asy12
-rw-r--r--graphics/asymptote/base/v3d.asy643
-rw-r--r--graphics/asymptote/base/v3dheadertypes.asy66
-rw-r--r--graphics/asymptote/base/v3dtypes.asy34
-rw-r--r--graphics/asymptote/base/webgl/asygl.js4
-rw-r--r--graphics/asymptote/base/x11colors.asy2
48 files changed, 1721 insertions, 605 deletions
diff --git a/graphics/asymptote/base/asy-mode.el b/graphics/asymptote/base/asy-mode.el
index ec3a3746d7..9f6eda793c 100644
--- a/graphics/asymptote/base/asy-mode.el
+++ b/graphics/asymptote/base/asy-mode.el
@@ -110,7 +110,7 @@ Some variables can be customized: M-x customize-group <RET> asymptote <RET>."
(require 'font-lock)
(require 'cc-mode)
-(require 'cl) ;; Common Lisp extensions for Emacs
+(require 'cl-lib) ;; Common Lisp extensions for Emacs
(require 'compile)
(require 'wid-edit)
@@ -637,6 +637,9 @@ Fields are defined as 'field1: field2.field3:field4' . Field=0 <-> all fields"
(if (locate-library "two-mode-mode")
(progn
+;; patch two-mode-mode.el for Emacs >= 23.
+ (defun make-local-hook (func))
+
(defvar lasy-fontify-asy-p nil
"Variable to communicate with `font-lock-unfontify-region'.
Internal use, don't set in any fashion.")
@@ -682,7 +685,8 @@ the current mode."
(setq lasy-fontify-asy-p (eq func 'asy-mode))
(funcall func)
(hack-local-variables)
- (two-mode-mode-setup)
+;; avoid infinite loop in two-mode-mode
+;; (two-mode-mode-setup)
(if two-mode-switch-hook
(run-hooks 'two-mode-switch-hook))
(if (eq font-lock-mode t)
diff --git a/graphics/asymptote/base/graph.asy b/graphics/asymptote/base/graph.asy
index 46a5d7d064..1d4dfc1bfd 100644
--- a/graphics/asymptote/base/graph.asy
+++ b/graphics/asymptote/base/graph.asy
@@ -2090,6 +2090,29 @@ guide polargraph(picture pic=currentpicture, real[] r, real[] theta,
},0,0,n-1);
}
+// Graph a parametric function with the control points specified to match the
+// derivative.
+guide graphwithderiv(pair f(real), pair fprime(real), real a, real b,
+ int n=ngraph # 10) {
+ guide toreturn;
+ real segmentlen = (b - a) / n;
+ pair[] points = new pair[n+1];
+ pair[] derivs = new pair[n+1];
+ real derivfactor = segmentlen / 3;
+ for (int i = 0; i <= n; ++i) {
+ real t = interp(a, b, i/n);
+ points[i] = f(t);
+ derivs[i] = fprime(t) * derivfactor;
+ }
+
+ toreturn = points[0];
+ for (int i = 1; i <= n; ++i) {
+ toreturn = toreturn .. controls (points[i-1] + derivs[i-1])
+ and (points[i] - derivs[i]) .. points[i];
+ }
+ return toreturn;
+}
+
void errorbar(picture pic, pair z, pair dp, pair dm, pen p=currentpen,
real size=0)
{
diff --git a/graphics/asymptote/base/math.asy b/graphics/asymptote/base/math.asy
index 3dde1b9dd4..d0ce523340 100644
--- a/graphics/asymptote/base/math.asy
+++ b/graphics/asymptote/base/math.asy
@@ -325,45 +325,45 @@ real interpolate(real[] x, real[] y, real x0)
private string nopoint="point not found";
// Return the nth intersection time of path g with the vertical line through x.
-real time(path g, real x, int n=0)
+real time(path g, real x, int n=0, real fuzz=-1)
{
- real[] t=times(g,x);
+ real[] t=times(g,x,fuzz);
if(t.length <= n) abort(nopoint);
return t[n];
}
// Return the nth intersection time of path g with the horizontal line through
// (0,z.y).
-real time(path g, explicit pair z, int n=0)
+real time(path g, explicit pair z, int n=0, real fuzz=-1)
{
- real[] t=times(g,z);
+ real[] t=times(g,z,fuzz);
if(t.length <= n) abort(nopoint);
return t[n];
}
// Return the nth y value of g at x.
-real value(path g, real x, int n=0)
+real value(path g, real x, int n=0, real fuzz=-1)
{
- return point(g,time(g,x,n)).y;
+ return point(g,time(g,x,n,fuzz)).y;
}
// Return the nth x value of g at y=z.y.
-real value(path g, explicit pair z, int n=0)
+real value(path g, explicit pair z, int n=0, real fuzz=-1)
{
- return point(g,time(g,(0,z.y),n)).x;
+ return point(g,time(g,(0,z.y),n,fuzz)).x;
}
// Return the nth slope of g at x.
-real slope(path g, real x, int n=0)
+real slope(path g, real x, int n=0, real fuzz=-1)
{
- pair a=dir(g,time(g,x,n));
+ pair a=dir(g,time(g,x,n,fuzz));
return a.y/a.x;
}
// Return the nth slope of g at y=z.y.
-real slope(path g, explicit pair z, int n=0)
+real slope(path g, explicit pair z, int n=0, real fuzz=-1)
{
- pair a=dir(g,time(g,(0,z.y),n));
+ pair a=dir(g,time(g,(0,z.y),n,fuzz));
return a.y/a.x;
}
diff --git a/graphics/asymptote/base/plain.asy b/graphics/asymptote/base/plain.asy
index 365aad02c7..cac6aa0722 100644
--- a/graphics/asymptote/base/plain.asy
+++ b/graphics/asymptote/base/plain.asy
@@ -150,7 +150,13 @@ void initdefaults()
// Return the sequence n,...,m
int[] sequence(int n, int m)
{
- return sequence(new int(int x){return x;},m-n+1)+n;
+ return n+sequence(m-n+1);
+}
+
+// Return the sequence n,...,m skipping by skip
+int[] sequence(int n, int m, int skip)
+{
+ return n+skip*sequence((m-n)#skip+1);
}
int[] reverse(int n) {return sequence(new int(int x){return n-1-x;},n);}
diff --git a/graphics/asymptote/base/plain_boxes.asy b/graphics/asymptote/base/plain_boxes.asy
index 50501a4089..9576caff55 100644
--- a/graphics/asymptote/base/plain_boxes.asy
+++ b/graphics/asymptote/base/plain_boxes.asy
@@ -28,7 +28,7 @@ path roundbox(frame dest, frame src=dest, real xmargin=0, real ymargin=xmargin,
(dw,b)--(a-dw,b){right}..{down}
(a,b-dw)--(a,dw){down}..{left}
(a-dw,0)--(dw,0){left}..{up}cycle);
-
+
frame F;
if(above == false) {
filltype.fill(F,g,p);
@@ -81,7 +81,7 @@ typedef path envelope(frame dest, frame src=dest, real xmargin=0,
filltype filltype=NoFill, bool above=true);
object object(Label L, envelope e, real xmargin=0, real ymargin=xmargin,
- pen p=currentpen, filltype filltype=NoFill, bool above=true)
+ pen p=currentpen, filltype filltype=NoFill, bool above=true)
{
object F;
F.L=L.copy();
@@ -93,9 +93,9 @@ object object(Label L, envelope e, real xmargin=0, real ymargin=xmargin,
return F;
}
-object draw(picture pic=currentpicture, Label L, envelope e,
+object draw(picture pic=currentpicture, Label L, envelope e,
real xmargin=0, real ymargin=xmargin, pen p=currentpen,
- filltype filltype=NoFill, bool above=true)
+ filltype filltype=NoFill, bool above=true)
{
object F=object(L,e,xmargin,ymargin,p,filltype,above);
pic.add(new void (frame f, transform t) {
@@ -115,7 +115,7 @@ object draw(picture pic=currentpicture, Label L, envelope e, pair position,
return draw(pic,Label(L,position),e,xmargin,ymargin,p,filltype,above);
}
-pair point(object F, pair dir, transform t=identity())
+pair point(object F, pair dir, transform t=identity())
{
pair m=min(F.g);
pair M=max(F.g);
diff --git a/graphics/asymptote/base/plain_constants.asy b/graphics/asymptote/base/plain_constants.asy
index 136b354021..6cca1406cf 100644
--- a/graphics/asymptote/base/plain_constants.asy
+++ b/graphics/asymptote/base/plain_constants.asy
@@ -31,9 +31,9 @@ restricted pair WSW=unit(W+SW);
restricted pair SSW=unit(S+SW);
restricted pair SSE=unit(S+SE);
restricted pair ESE=unit(E+SE);
-
+
restricted real sqrtEpsilon=sqrt(realEpsilon);
-restricted pair Align=sqrtEpsilon*NE;
+restricted pair Align=sqrtEpsilon*NE;
restricted int mantissaBits=ceil(-log(realEpsilon)/log(2))+1;
restricted transform identity;
@@ -108,7 +108,7 @@ void write(file file, string s="", bool3 b, suffix suffix=none)
else write("default",suffix);
}
-void write(string s="", bool3 b, suffix suffix=endl)
+void write(string s="", bool3 b, suffix suffix=endl)
{
write(stdout,s,b,suffix);
}
@@ -128,32 +128,32 @@ bool3 operator cast(bool b)
return B;
}
-bool operator == (bool3 a, bool3 b)
+bool operator == (bool3 a, bool3 b)
{
return a.set == b.set && (!a.set || (a.value == b.value));
}
-bool operator != (bool3 a, bool3 b)
+bool operator != (bool3 a, bool3 b)
{
return a.set != b.set || (a.set && (a.value != b.value));
}
-bool operator == (bool3 a, bool b)
+bool operator == (bool3 a, bool b)
{
return a.set && a.value == b;
}
-bool operator != (bool3 a, bool b)
+bool operator != (bool3 a, bool b)
{
return !a.set || a.value != b;
}
-bool operator == (bool a, bool3 b)
+bool operator == (bool a, bool3 b)
{
return b.set && b.value == a;
}
-bool operator != (bool a, bool3 b)
+bool operator != (bool a, bool3 b)
{
return !b.set || b.value != a;
}
diff --git a/graphics/asymptote/base/plain_filldraw.asy b/graphics/asymptote/base/plain_filldraw.asy
index 026f2cee6c..eaf1257169 100644
--- a/graphics/asymptote/base/plain_filldraw.asy
+++ b/graphics/asymptote/base/plain_filldraw.asy
@@ -3,7 +3,7 @@ void makedraw(frame f, path g, pen p, int depth=mantissaBits)
{
if(depth == 0) return;
--depth;
-
+
path n=nib(p);
for(int i=0; i < size(g); ++i)
fill(f,shift(point(g,i))*n,p);
@@ -88,7 +88,7 @@ void filloutside(frame f, path[] g, pen p=currentpen, bool copy=true)
fill(f,complement(f,g),p+evenodd,copy);
}
-struct filltype
+struct filltype
{
typedef void fill2(frame f, path[] g, pen fillpen);
fill2 fill2;
@@ -101,7 +101,7 @@ struct filltype
static int Draw=3;
static int NoFill=4;
static int UnFill=5;
-
+
void operator init(int type=0, pen fillpen=nullpen, pen drawpen=nullpen,
fill2 fill2) {
this.type=type;
@@ -112,7 +112,7 @@ struct filltype
void fill(frame f, path[] g, pen p) {fill2(f,g,p);}
}
-path[] margin(path[] g, real xmargin, real ymargin)
+path[] margin(path[] g, real xmargin, real ymargin)
{
if(xmargin != 0 || ymargin != 0) {
pair M=max(g);
@@ -123,7 +123,7 @@ path[] margin(path[] g, real xmargin, real ymargin)
real yfactor=height > 0 ? (height+2ymargin)/height : 1;
g=scale(xfactor,yfactor)*g;
g=shift(0.5*(M+m)-0.5*(max(g)+min(g)))*g;
- }
+ }
return g;
}
@@ -174,7 +174,7 @@ filltype UnFill(real xmargin=0, real ymargin=xmargin)
});
}
-filltype FillDraw=FillDraw(), Fill=Fill(), Draw=Draw(), UnFill=UnFill();
+filltype FillDraw=FillDraw(), Fill=Fill(), Draw=Draw(), UnFill=UnFill();
// Fill varying radially from penc at the center of the bounding box to
// penr at the edge.
diff --git a/graphics/asymptote/base/plain_margins.asy b/graphics/asymptote/base/plain_margins.asy
index fbd0163050..c03b3a2b52 100644
--- a/graphics/asymptote/base/plain_margins.asy
+++ b/graphics/asymptote/base/plain_margins.asy
@@ -27,7 +27,7 @@ margin operator +(margin ma, margin mb)
}
margin NoMargin()
-{
+{
return new marginT(path g, pen) {
marginT margin;
margin.begin=margin.end=0;
@@ -35,9 +35,9 @@ margin NoMargin()
return margin;
};
}
-
+
margin Margin(real begin, real end=begin)
-{
+{
return new marginT(path g, pen p) {
marginT margin;
real factor=labelmargin(p);
@@ -47,9 +47,9 @@ margin Margin(real begin, real end=begin)
return margin;
};
}
-
+
margin PenMargin(real begin, real end=begin)
-{
+{
return new marginT(path g, pen p) {
marginT margin;
real factor=linewidth(p);
@@ -59,9 +59,9 @@ margin PenMargin(real begin, real end=begin)
return margin;
};
}
-
+
margin DotMargin(real begin, real end=begin)
-{
+{
return new marginT(path g, pen p) {
marginT margin;
real margindot(real x) {return x > 0 ? dotfactor*x : x;}
@@ -72,9 +72,9 @@ margin DotMargin(real begin, real end=begin)
return margin;
};
}
-
+
margin TrueMargin(real begin, real end=begin)
-{
+{
return new marginT(path g, pen p) {
marginT margin;
margin.begin=begin;
@@ -83,7 +83,7 @@ margin TrueMargin(real begin, real end=begin)
return margin;
};
}
-
+
margin NoMargin=NoMargin(),
BeginMargin=Margin(1,0),
Margin=Margin(0,1),
diff --git a/graphics/asymptote/base/plain_markers.asy b/graphics/asymptote/base/plain_markers.asy
index 250e1701eb..c6109d4e6c 100644
--- a/graphics/asymptote/base/plain_markers.asy
+++ b/graphics/asymptote/base/plain_markers.asy
@@ -5,7 +5,7 @@ real legendmargin=10;
real legendmaxrelativewidth=1;
// Return a unit polygon with n sides.
-path polygon(int n)
+path polygon(int n)
{
guide g;
for(int i=0; i < n; ++i) g=g--expi(2pi*(i+0.5)/n-0.5*pi);
@@ -14,7 +14,7 @@ path polygon(int n)
// Return a unit n-point cyclic cross, with optional inner radius r and
// end rounding.
-path cross(int n, bool round=true, real r=0)
+path cross(int n, bool round=true, real r=0)
{
assert(n > 1);
real r=min(r,1);
@@ -41,7 +41,8 @@ path cross(int n, bool round=true, real r=0)
return g--cycle;
}
-path[] plus=(-1,0)--(1,0)^^(0,-1)--(0,1);
+path plus=rotate(45)*cross(4);
+path diamond=rotate(45)*polygon(4);
typedef void markroutine(picture pic=currentpicture, frame f, path g);
@@ -98,9 +99,9 @@ struct marker {
markroutine(pic,f,g);
};
}
-
+
marker marker(frame f=newframe, markroutine markroutine=marknodes,
- bool above=true)
+ bool above=true)
{
marker m=new marker;
m.f=f;
@@ -147,15 +148,18 @@ real circlescale=0.85;
path[] MarkPath={scale(circlescale)*unitcircle,
polygon(3),polygon(4),polygon(5),invert*polygon(3),
- cross(4),cross(6)};
+ cross(4),cross(6),diamond,plus};
+
+int[] MarkFillable={0,1,2,3,4,7};
marker[] Mark=sequence(new marker(int i) {return marker(MarkPath[i]);},
MarkPath.length);
-marker[] MarkFill=sequence(new marker(int i) {return marker(MarkPath[i],Fill);},
- MarkPath.length-2);
+marker[] MarkFill=sequence(new marker(int i) {
+ return marker(MarkPath[MarkFillable[i]],Fill);
+ },MarkFillable.length);
-marker Mark(int n)
+marker Mark(int n)
{
n=n % (Mark.length+MarkFill.length);
if(n < Mark.length) return Mark[n];
@@ -194,7 +198,7 @@ picture legend(Legend[] Legend, int perline=1, real linelength,
if(Legend.length == 0)
return inset;
- // Check for legend entries with lines:
+ // Check for legend entries with lines:
bool bLineEntriesAvailable=false;
for(int i=0; i < Legend.length; ++i) {
if(Legend[i].p != invisible) {
@@ -231,8 +235,8 @@ picture legend(Legend[] Legend, int perline=1, real linelength,
totalwidth += size(pic).x;
}
}
- // Does everything fit into one line?
- if(((perline < 1) || (perline >= Legend.length)) &&
+ // Does everything fit into one line?
+ if(((perline < 1) || (perline >= Legend.length)) &&
(maxwidth >= totalwidth+(totalwidth/Legend.length)*
(Legend.length-1)*(hskip-1))) {
// One-line legend
@@ -285,7 +289,7 @@ frame legend(picture pic=currentpicture, int perline=1,
real xmargin=legendmargin, real ymargin=xmargin,
real linelength=legendlinelength,
real hskip=legendhskip, real vskip=legendvskip,
- real maxwidth=perline == 0 ?
+ real maxwidth=perline == 0 ?
legendmaxrelativewidth*size(pic).x : 0, real maxheight=0,
bool hstretch=false, bool vstretch=false, pen p=currentpen)
{
@@ -312,7 +316,7 @@ void dot(frame f, pair z, pen p=currentpen, filltype filltype=dotfilltype)
if(filltype == Fill)
draw(f,z,dotsize(p)+p);
else {
- real s=0.5*(dotsize(p)-linewidth(p));
+ real s=0.5*(dotsize(p)-linewidth(p));
if(s <= 0) return;
path g=shift(z)*scale(s)*unitcircle;
begingroup(f);
@@ -398,4 +402,4 @@ marker dot(pen p=currentpen, filltype filltype=dotfilltype)
}
marker dot=dot();
-
+
diff --git a/graphics/asymptote/base/plain_paths.asy b/graphics/asymptote/base/plain_paths.asy
index 8bb5250db5..49d2f4ac0b 100644
--- a/graphics/asymptote/base/plain_paths.asy
+++ b/graphics/asymptote/base/plain_paths.asy
@@ -51,32 +51,32 @@ path[] operator cast(guide g)
return new path[] {(path) g};
}
-path[] operator ^^ (path p, path q)
+path[] operator ^^ (path p, path q)
{
return new path[] {p,q};
}
-path[] operator ^^ (path p, explicit path[] q)
+path[] operator ^^ (path p, explicit path[] q)
{
return concat(new path[] {p},q);
}
-path[] operator ^^ (explicit path[] p, path q)
+path[] operator ^^ (explicit path[] p, path q)
{
return concat(p,new path[] {q});
}
-path[] operator ^^ (explicit path[] p, explicit path[] q)
+path[] operator ^^ (explicit path[] p, explicit path[] q)
{
return concat(p,q);
}
-path[] operator * (transform t, explicit path[] p)
+path[] operator * (transform t, explicit path[] p)
{
return sequence(new path(int i) {return t*p[i];},p.length);
}
-pair[] operator * (transform t, pair[] z)
+pair[] operator * (transform t, pair[] z)
{
return sequence(new pair(int i) {return t*z[i];},z.length);
}
@@ -93,7 +93,7 @@ void write(file file, string s="", explicit path[] x, suffix suffix=none)
write(file,suffix);
}
-void write(string s="", explicit path[] x, suffix suffix=endl)
+void write(string s="", explicit path[] x, suffix suffix=endl)
{
write(stdout,s,x,suffix);
}
@@ -110,7 +110,7 @@ void write(file file, string s="", explicit guide[] x, suffix suffix=none)
write(file,suffix);
}
-void write(string s="", explicit guide[] x, suffix suffix=endl)
+void write(string s="", explicit guide[] x, suffix suffix=endl)
{
write(stdout,s,x,suffix);
}
@@ -156,8 +156,8 @@ pair[] intersectionpoints(explicit path[] p, explicit path[] q, real fuzz=-1)
struct slice {
path before,after;
}
-
-slice cut(path p, path knife, int n)
+
+slice cut(path p, path knife, int n)
{
slice s;
real[][] T=intersections(p,knife);
@@ -169,7 +169,7 @@ slice cut(path p, path knife, int n)
return s;
}
-slice firstcut(path p, path knife)
+slice firstcut(path p, path knife)
{
return cut(p,knife,0);
}
@@ -331,16 +331,16 @@ pair inside(path p, pen fillrule=currentpen)
}
// Return all intersection times of path g with the vertical line through (x,0).
-real[] times(path p, real x)
+real[] times(path p, real x, real fuzz=-1)
{
- return intersections(p,(x,0),(x,1));
+ return intersections(p,(x,0),(x,1),fuzz);
}
// Return all intersection times of path g with the horizontal line through
// (0,z.y).
-real[] times(path p, explicit pair z)
+real[] times(path p, explicit pair z, real fuzz=-1)
{
- return intersections(p,(0,z.y),(1,z.y));
+ return intersections(p,(0,z.y),(1,z.y),fuzz);
}
path randompath(int n, bool cumulate=true, interpolate join=operator ..)
@@ -349,7 +349,7 @@ path randompath(int n, bool cumulate=true, interpolate join=operator ..)
pair w;
for(int i=0; i <= n; ++i) {
pair z=(unitrand()-0.5,unitrand()-0.5);
- if(cumulate) w += z;
+ if(cumulate) w += z;
else w=z;
g=join(g,w);
}
diff --git a/graphics/asymptote/base/plain_pens.asy b/graphics/asymptote/base/plain_pens.asy
index b846569658..2e3a4449a3 100644
--- a/graphics/asymptote/base/plain_pens.asy
+++ b/graphics/asymptote/base/plain_pens.asy
@@ -8,7 +8,7 @@ pen longdashed=linetype(new real[] {24,8});
pen dashdotted=linetype(new real[] {8,8,0,8});
pen longdashdotted=linetype(new real[] {24,8,0,8});
-pen linetype(string pattern, real offset=0, bool scale=true, bool adjust=true)
+pen linetype(string pattern, real offset=0, bool scale=true, bool adjust=true)
{
return linetype((real[]) split(pattern),offset,scale,adjust);
}
@@ -151,7 +151,7 @@ pen[] monoPen={solid,dashed,dotted,longdashed,dashdotted,
longdashdotted};
monoPen.cyclic=true;
-pen Pen(int n)
+pen Pen(int n)
{
return (settings.gray || settings.bw) ? monoPen[n] : colorPen[n];
}
@@ -161,12 +161,12 @@ pen Pentype(int n)
return (settings.gray || settings.bw) ? monoPen[n] : monoPen[n]+colorPen[n];
}
-real dotsize(pen p=currentpen)
+real dotsize(pen p=currentpen)
{
return dotfactor*linewidth(p);
}
-pen fontsize(real size)
+pen fontsize(real size)
{
return fontsize(size,1.2*size);
}
@@ -189,7 +189,7 @@ void usetypescript(string s, string encoding="")
texpreamble(s);
}
-pen font(string name, string options="")
+pen font(string name, string options="")
{
// Work around misalignment in ConTeXt switchtobodyfont if font is not found.
return fontcommand(settings.tex == "context" ?
@@ -199,7 +199,7 @@ pen font(string name, string options="")
"\font\ASYfont="+name+"\ASYfont");
}
-pen font(string name, real size, string options="")
+pen font(string name, real size, string options="")
{
string s=(string) (size/pt)+"pt";
if(settings.tex == "context")
@@ -207,7 +207,7 @@ pen font(string name, real size, string options="")
return fontsize(size)+font(name+" at "+s);
}
-pen font(string encoding, string family, string series, string shape)
+pen font(string encoding, string family, string series, string shape)
{
return fontcommand("\usefont{"+encoding+"}{"+family+"}{"+series+"}{"+shape+
"}");
@@ -316,16 +316,21 @@ real[] rgba(pen p)
return a;
}
+pen rgb(real[] a)
+{
+ return rgb(a[0],a[1],a[2]);
+}
+
pen rgba(real[] a)
{
return rgb(a[0],a[1],a[2])+opacity(a[3]);
}
// Return a pen corresponding to a given 6-character RGB hexadecimal string.
-pen rgb(string s)
+pen rgb(string s)
{
int offset=substr(s,0,1) == '#' ? 1 : 0;
- real value(string s, int i) {return hex(substr(s,2i+offset,2))/255;}
+ real value(string s, int i) {return byteinv(hex(substr(s,2i+offset,2)));}
return rgb(value(s,0),value(s,1),value(s,2));
}
diff --git a/graphics/asymptote/base/plain_picture.asy b/graphics/asymptote/base/plain_picture.asy
index c0c189ee69..13619e80ab 100644
--- a/graphics/asymptote/base/plain_picture.asy
+++ b/graphics/asymptote/base/plain_picture.asy
@@ -59,10 +59,10 @@ struct coords3 {
}
}
}
-
+
// scaleT and Legend <<<
typedef real scalefcn(real x);
-
+
struct scaleT {
scalefcn T,Tinv;
bool logarithmic;
@@ -86,7 +86,7 @@ scaleT operator init()
scaleT S=scaleT(identity,identity);
return S;
}
-
+
typedef void boundRoutine();
struct autoscaleT {
@@ -97,11 +97,11 @@ struct autoscaleT {
bool automin=false, automax=false;
bool automin() {return automin && scale.automin;}
bool automax() {return automax && scale.automax;}
-
+
real T(real x) {return postscale.T(scale.T(x));}
scalefcn T() {return scale.logarithmic ? postscale.T : T;}
real Tinv(real x) {return scale.Tinv(postscale.Tinv(x));}
-
+
autoscaleT copy() {
autoscaleT dest=new autoscaleT;
dest.scale=scale.copy();
@@ -120,7 +120,7 @@ struct ScaleT {
autoscaleT x;
autoscaleT y;
autoscaleT z;
-
+
ScaleT copy() {
ScaleT dest=new ScaleT;
dest.set=set;
@@ -240,15 +240,15 @@ struct picture { // <<<1
return b;
}
}
-
+
bounds bounds;
bounds3 bounds3;
-
+
// Other Fields <<<2
// Transform to be applied to this picture.
transform T;
transform3 T3;
-
+
// The internal representation of the 3D user bounds.
private pairOrTriple umin, umax;
private bool usetx, usety, usetz;
@@ -267,14 +267,14 @@ struct picture { // <<<1
// Fixed unitsizes in the x y, and z directions; zero means use
// xsize, ysize, and zsize.
real xunitsize=0, yunitsize=0, zunitsize=0;
-
+
// If true, the x and y directions must be scaled by the same amount.
bool keepAspect=true;
// A fixed scaling transform.
bool fixed;
transform fixedscaling;
-
+
// Init and erase <<<2
void init() {
umin.init();
@@ -283,7 +283,7 @@ struct picture { // <<<1
T3=identity(4);
}
init();
-
+
// Erase the current picture, retaining bounds.
void clear() {
nodes.delete();
@@ -300,7 +300,7 @@ struct picture { // <<<1
scale=new ScaleT;
init();
}
-
+
// Empty <<<2
bool empty2() {
return nodes.length == 0;
@@ -313,7 +313,7 @@ struct picture { // <<<1
bool empty() {
return empty2() && empty3();
}
-
+
// User min/max <<<2
pair userMin2() {return bounds.userMin(); }
pair userMax2() {return bounds.userMax(); }
@@ -373,27 +373,27 @@ struct picture { // <<<1
umin.x=x;
usetx=true;
}
-
+
void userMiny3(real y) {
umin.y=y;
usety=true;
}
-
+
void userMinz3(real z) {
umin.z=z;
usetz=true;
}
-
+
void userMaxx3(real x) {
umax.x=x;
usetx=true;
}
-
+
void userMaxy3(real y) {
umax.y=y;
usety=true;
}
-
+
void userMaxz3(real z) {
umax.z=z;
usetz=true;
@@ -409,7 +409,7 @@ struct picture { // <<<1
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);
@@ -419,7 +419,7 @@ struct picture { // <<<1
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);
}
-
+
// Cache the current user-space bounding box x coodinates
void userBoxX3(real min, real max, binop m=min, binop M=max) {
if (usetx) {
@@ -462,7 +462,7 @@ struct picture { // <<<1
userBoxY3(min.y,max.y);
userBoxZ3(min.z,max.z);
}
-
+
// Add drawer <<<2
void add(drawerBound d, bool exact=false, bool above=true) {
uptodate=false;
@@ -472,7 +472,7 @@ struct picture { // <<<1
else
nodes.insert(0,node(d));
}
-
+
// Faster implementation of most common case.
void addExactAbove(drawerBound d) {
uptodate=false;
@@ -518,13 +518,13 @@ struct picture { // <<<1
bounds.addPoint(user,truesize);
//userBox(user,user);
}
-
+
// Add a point to the sizing, accounting also for the size of the pen.
void addPoint(pair user, pair truesize=0, pen p) {
addPoint(user,truesize+min(p));
addPoint(user,truesize+max(p));
}
-
+
void addPoint(triple user, triple truesize=(0,0,0)) {
bounds3.point.push(user,truesize);
userBox3(user,user);
@@ -618,7 +618,7 @@ struct picture { // <<<1
}
void append(coords3 point, coords3 min, coords3 max, transform3 t,
- bounds3 bounds)
+ bounds3 bounds)
{
// Add the coord info to this picture.
if(t == identity4) {
@@ -638,7 +638,7 @@ struct picture { // <<<1
point.push(t,bounds.max,bounds.max,bounds.max);
}
}
-
+
// 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,
@@ -660,9 +660,9 @@ struct picture { // <<<1
return identity(4);
coords3 Coords;
-
+
append(Coords,Coords,Coords,T3,bounds3);
-
+
real sx;
if(xunitsize == 0) {
if(xsize != 0) sx=calculateScaling("x",Coords.x,xsize,warn);
@@ -709,7 +709,7 @@ struct picture { // <<<1
triple m, triple M) {
frame f;
for(node3 n : nodes3) {
- xasyKEY(n.key);
+ xasyKEY(nodes3[0].key);
n.d(f,t,T0,pic,P,m,M);
}
return f;
@@ -757,7 +757,7 @@ struct picture { // <<<1
frame f=fit(fixedscaling);
pair d=size(f);
static real epsilon=100*realEpsilon;
- if(d.x > xsize*(1+epsilon))
+ if(d.x > xsize*(1+epsilon))
warning("xlimit","frame exceeds xlimit: "+(string) d.x+" > "+
(string) xsize);
if(d.y > ysize*(1+epsilon))
@@ -765,7 +765,7 @@ struct picture { // <<<1
(string) ysize);
return f;
}
-
+
// Calculate additional scaling required if only an approximate picture
// size estimate is available.
transform scale(frame f, real xsize=this.xsize, real ysize=this.ysize,
@@ -836,24 +836,24 @@ struct picture { // <<<1
bool keepAspect=this.keepAspect, bool warn=true) {
return min(calculateTransform(xsize,ysize,keepAspect,warn));
}
-
+
pair max(real xsize=this.xsize, real ysize=this.ysize,
bool keepAspect=this.keepAspect, bool warn=true) {
return max(calculateTransform(xsize,ysize,keepAspect,warn));
}
-
+
triple min3(real xsize=this.xsize3, real ysize=this.ysize3,
real zsize=this.zsize3, bool keepAspect=this.keepAspect,
bool warn=true, projection P) {
return min(calculateTransform3(xsize,ysize,zsize,keepAspect,warn,P));
}
-
+
triple max3(real xsize=this.xsize3, real ysize=this.ysize3,
real zsize=this.zsize3, bool keepAspect=this.keepAspect,
bool warn=true, projection P) {
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,
@@ -880,7 +880,7 @@ struct picture { // <<<1
fitter(prefix,this,format,xsize,ysize,keepAspect,view,options,script,
light,P);
}
-
+
// Fit a 3D picture.
frame fit3(projection P=currentprojection) {
if(settings.render == 0) return fit(P);
@@ -895,7 +895,7 @@ struct picture { // <<<1
// In case only an approximate picture size estimate is available, return the
// fitted frame slightly scaled (including labels and true size distances)
- // so that it precisely meets the given size specification.
+ // so that it precisely meets the given size specification.
frame scale(real xsize=this.xsize, real ysize=this.ysize,
bool keepAspect=this.keepAspect) {
frame f=fit(xsize,ysize,keepAspect);
@@ -905,7 +905,7 @@ struct picture { // <<<1
}
// Copying <<<2
-
+
// Copies enough information to yield the same userMin/userMax.
void userCopy2(picture pic) {
userMinx2(pic.userMin2().x);
@@ -921,12 +921,12 @@ struct picture { // <<<1
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() {
@@ -954,14 +954,14 @@ struct picture { // <<<1
dest.uptodate=uptodate;
dest.bounds=bounds.copy();
dest.bounds3=bounds3.copy();
-
+
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;
}
@@ -984,7 +984,7 @@ struct picture { // <<<1
dest.uptodate=uptodate;
dest.bounds=bounds.transformed(t);
dest.bounds3=bounds3.copy();
-
+
dest.bounds.exact=false;
dest.xsize=xsize; dest.ysize=ysize;
@@ -993,7 +993,7 @@ struct picture { // <<<1
dest.xunitsize=xunitsize; dest.yunitsize=yunitsize;
dest.zunitsize=zunitsize;
dest.fixed=fixed; dest.fixedscaling=fixedscaling;
-
+
return dest;
}
@@ -1007,7 +1007,7 @@ struct picture { // <<<1
// objects added to it that should not be included in this picture.
if(src == this) abort("cannot add picture to itself");
-
+
uptodate=false;
picture srcCopy=src.drawcopy();
@@ -1018,7 +1018,7 @@ struct picture { // <<<1
add(f,srcCopy.fit(t,T*srcCopy.T,m,M),group,filltype,above);
}));
}
-
+
if(srcCopy.nodes3.length > 0) {
nodes3.push(node3(new void(frame f, transform3 t, transform3 T3,
picture pic, projection P, triple m, triple M)
@@ -1026,13 +1026,13 @@ struct picture { // <<<1
add(f,srcCopy.fit3(t,T3*srcCopy.T3,pic,P,m,M),group,above);
}));
}
-
+
legend.append(src.legend);
-
+
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);
-
+
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);
@@ -1087,7 +1087,7 @@ void size3(picture pic=currentpicture, real x, real y=x, real z=y,
pic.size3(x,y,z,keepAspect);
}
-void unitsize(picture pic=currentpicture, real x, real y=x, real z=y)
+void unitsize(picture pic=currentpicture, real x, real y=x, real z=y)
{
pic.unitsize(x,y,z);
}
@@ -1113,14 +1113,14 @@ pair min(picture pic, bool user=false)
pair z=pic.min(t);
return user ? inverse(t)*z : z;
}
-
+
pair max(picture pic, bool user=false)
{
transform t=pic.calculateTransform();
pair z=pic.max(t);
return user ? inverse(t)*z : z;
}
-
+
pair size(picture pic, bool user=false)
{
transform t=pic.calculateTransform();
@@ -1132,7 +1132,7 @@ pair size(picture pic, bool user=false)
}
// Frame Alignment <<<
-pair rectify(pair dir)
+pair rectify(pair dir)
{
real scale=max(abs(dir.x),abs(dir.y));
if(scale != 0) dir *= 0.5/scale;
@@ -1161,13 +1161,13 @@ path[] align(path[] g, transform t=identity(), pair position,
}
// Returns a transform for aligning frame f in the direction align
-transform shift(frame f, pair 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)
+frame align(frame f, pair align)
{
return shift(f,align)*f;
}
@@ -1448,7 +1448,7 @@ void clip(picture pic=currentpicture, path[] g, bool stroke=false,
}
void beginclip(picture pic=currentpicture, path[] g, bool stroke=false,
- pen fillrule=currentpen, bool copy=true)
+ pen fillrule=currentpen, bool copy=true)
{
if(copy)
g=copy(g);
@@ -1505,7 +1505,7 @@ void filloutside(picture pic=currentpicture, path[] g, pen p=currentpen,
pic.addPath(g);
}
-// Use a fixed scaling to map user coordinates in box(min,max) to the
+// Use a fixed scaling to map user coordinates in box(min,max) to the
// desired picture size.
transform fixedscaling(picture pic=currentpicture, pair min, pair max,
pen p=nullpen, bool warn=false)
@@ -1671,7 +1671,7 @@ void begin(picture pic=currentpicture, string name, string id="",
void end(picture pic=currentpicture)
{
if(!latex() || !pdf()) return;
- tex(pic,"\end{ocg}");
+ tex(pic,"\end{ocg}%");
layer(pic);
}
diff --git a/graphics/asymptote/base/plain_prethree.asy b/graphics/asymptote/base/plain_prethree.asy
index 968ae2943a..8866396255 100644
--- a/graphics/asymptote/base/plain_prethree.asy
+++ b/graphics/asymptote/base/plain_prethree.asy
@@ -76,7 +76,7 @@ struct projection {
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() {
@@ -137,8 +137,8 @@ struct projection {
(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);
@@ -161,7 +161,7 @@ projection currentprojection;
struct light {
real[][] diffuse;
- real[][] specular;
+ real[][] specular; // For PRC only
pen background=nullpen; // Background color of the 3D canvas.
real specularfactor;
triple[] position; // Only directional lights are currently implemented.
@@ -169,14 +169,14 @@ struct light {
transform3 T=identity(4); // Transform to apply to normal vectors.
bool on() {return position.length > 0;}
-
+
void operator init(pen[] diffuse,
pen[] specular=diffuse, pen background=nullpen,
real specularfactor=1,
triple[] position) {
int n=diffuse.length;
assert(specular.length == n && position.length == n);
-
+
this.diffuse=new real[n][];
this.specular=new real[n][];
this.background=background;
@@ -213,4 +213,3 @@ struct light {
}
light currentlight;
-
diff --git a/graphics/asymptote/base/plain_scaling.asy b/graphics/asymptote/base/plain_scaling.asy
index 5bed3338e9..4c6beae655 100644
--- a/graphics/asymptote/base/plain_scaling.asy
+++ b/graphics/asymptote/base/plain_scaling.asy
@@ -19,7 +19,7 @@ struct coord {
coord copy() {
return build(user, truesize);
}
-
+
void clip(real min, real max) {
user=min(max(user,min),max);
truesize=0;
@@ -47,7 +47,7 @@ coord[] maxcoords(coord[] in, bool operator <= (coord,coord))
coord[] c;
int n=in.length;
-
+
if(n == 0)
return c;
@@ -151,15 +151,15 @@ struct coords2 {
}
}
void xclip(real min, real max) {
- for(int i=0; i < x.length; ++i)
+ 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)
+ 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;
@@ -211,7 +211,7 @@ real calculateScaling(string dir, coord[] m, coord[] M, real size,
// (a*user + b) + truesize >= 0:
A.push(new real[] {c.user,1,-1});
b.push(-c.truesize);
- }
+ }
void addMaxCoord(coord c) {
// (a*user + b) + truesize <= size:
A.push(new real[] {-c.user,-1,1});
@@ -239,12 +239,12 @@ real calculateScaling(string dir, coord[] m, coord[] M, real size,
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);
}
}
diff --git a/graphics/asymptote/base/plain_shipout.asy b/graphics/asymptote/base/plain_shipout.asy
index 388a03a557..fcc7f8e28a 100644
--- a/graphics/asymptote/base/plain_shipout.asy
+++ b/graphics/asymptote/base/plain_shipout.asy
@@ -11,7 +11,7 @@ string outprefix(string prefix=defaultfilename) {
return stripextension(prefix != "" ? prefix : outname());
}
-string outformat(string format="")
+string outformat(string format="")
{
if(format == "") format=settings.outformat;
if(format == "") format=nativeformat();
@@ -32,6 +32,10 @@ object embed3(string, frame, string, string, string, light, projection);
string Embed(string name, string text="", string options="", real width=0,
real height=0);
+bool primitive() { // Encode primitive objects
+ return settings.outformat == "html" || settings.outformat=="v3d";
+}
+
bool prconly(string format="")
{
return outformat(format) == "prc";
@@ -39,7 +43,7 @@ bool prconly(string format="")
bool prc0(string format="")
{
- return settings.prc && (outformat(format) == "pdf" || prconly() || settings.inlineimage );
+ return settings.outformat == "prc" || (settings.prc && (outformat(format) == "pdf" || prconly() || settings.inlineimage ));
}
bool prc(string format="") {
@@ -62,6 +66,14 @@ frame enclose(string prefix=defaultfilename, object F, string format="")
void deconstruct(picture pic=currentpicture)
{
+ if(currentpicture.nodes3.length > 0) {
+ if(currentpicture.xsize3 == 0 &&
+ currentpicture.ysize3 == 0 &&
+ currentpicture.zsize3 == 0)
+ currentpicture.size3(hypot(currentpicture.xsize,currentpicture.ysize));
+ currentpicture.size(0);
+ }
+
frame f;
transform t=pic.calculateTransform();
if(currentpicture.fitter == null)
@@ -95,7 +107,7 @@ void shipout(string prefix=defaultfilename, frame f,
}
return;
}
-
+
// Applications like LaTeX cannot handle large PostScript coordinates.
pair m=min(f);
int limit=2000;
diff --git a/graphics/asymptote/base/plain_strings.asy b/graphics/asymptote/base/plain_strings.asy
index a515861493..2e291f102f 100644
--- a/graphics/asymptote/base/plain_strings.asy
+++ b/graphics/asymptote/base/plain_strings.asy
@@ -49,13 +49,13 @@ triple gettriple(string name="", triple default=(0,0,0), string prompt="",
// returns a string with all occurrences of string 'before' in string 's'
// changed to string 'after'.
-string replace(string s, string before, string after)
+string replace(string s, string before, string after)
{
return replace(s,new string[][] {{before,after}});
}
// Like texify but don't convert embedded TeX commands: \${}
-string TeXify(string s)
+string TeXify(string s)
{
static string[][] t={{"&","\&"},{"%","\%"},{"_","\_"},{"#","\#"},{"<","$<$"},
{">","$>$"},{"|","$|$"},{"^","$\hat{\ }$"},
@@ -68,7 +68,7 @@ private string[][] trans1={{'\\',"\backslash "},
private string[][] trans2={{"\backslash ","$\backslash$"}};
// Convert string to TeX
-string texify(string s)
+string texify(string s)
{
return TeXify(replace(replace(s,trans1),trans2));
}
@@ -93,7 +93,7 @@ string[] split(string s, string delimiter="")
prune=true;
delimiter=" ";
}
-
+
string[] S;
int last=0;
int i;
@@ -130,7 +130,7 @@ string operator +(...string[] a)
return S;
}
-int system(string s)
+int system(string s)
{
return system(split(s));
}
@@ -161,8 +161,8 @@ string italic(string s)
return s != "" ? "{\it "+s+"}" : s;
}
-string baseline(string s, string template="\strut")
-{
+string baseline(string s, string template="\strut")
+{
return s != "" && settings.tex != "none" ? "\vphantom{"+template+"}"+s : s;
}
@@ -171,7 +171,7 @@ string math(string s)
return s != "" ? "$"+s+"$" : s;
}
-private void notimplemented(string text)
+private void notimplemented(string text)
{
abort(text+" is not implemented for the '"+settings.tex+"' TeX engine");
}
@@ -217,7 +217,7 @@ void usepackage(string s, string options="")
texpreamble(usepackage+"{"+s+"}");
}
-void pause(string w="Hit enter to continue")
+void pause(string w="Hit enter to continue")
{
write(w);
w=stdin;
diff --git a/graphics/asymptote/base/pstoedit.asy b/graphics/asymptote/base/pstoedit.asy
index 7baccd3ed6..8bd67e0911 100644
--- a/graphics/asymptote/base/pstoedit.asy
+++ b/graphics/asymptote/base/pstoedit.asy
@@ -15,4 +15,4 @@ void grestore(picture pic=currentpicture)
grestore(f);
},true);
}
-
+
diff --git a/graphics/asymptote/base/rational.asy b/graphics/asymptote/base/rational.asy
index a120c14123..aac3d5be9b 100644
--- a/graphics/asymptote/base/rational.asy
+++ b/graphics/asymptote/base/rational.asy
@@ -11,7 +11,7 @@ int gcd(int m, int n)
int r=m % n;
m=n;
n=r;
- }
+ }
return m;
}
diff --git a/graphics/asymptote/base/roundedpath.asy b/graphics/asymptote/base/roundedpath.asy
index 1a426f91dc..0029447327 100644
--- a/graphics/asymptote/base/roundedpath.asy
+++ b/graphics/asymptote/base/roundedpath.asy
@@ -1,7 +1,7 @@
// a function to round sharp edges of open and cyclic paths
// written by stefan knorr
-path roundedpath(path A, real R, real S = 1)
+path roundedpath(path A, real R, real S = 1)
// create rounded path from path A with radius R and scale S = 1
{
path RoundPath; // returned path
@@ -9,20 +9,20 @@ path roundedpath(path A, real R, real S = 1)
path LocalCirc; // local edge circle for intersection
real LocalTime; // local intersectiontime between . and ..
pair LocalPair; // local point to be added to 'RoundPath'
-
- int len=length(A); // length of given path 'A'
+
+ int len=length(A); // length of given path 'A'
bool PathClosed=cyclic(A); // true, if given path 'A' is cyclic
// initialisation: define first Point of 'RoundPath' as
if (PathClosed) // ? is 'A' cyclic
- RoundPath=scale(S)*point(point(A,0)--point(A,1), 0.5); // centerpoint of first straight subpath of 'A'
+ RoundPath=scale(S)*point(point(A,0)--point(A,1), 0.5); // centerpoint of first straight subpath of 'A'
else
RoundPath=scale(S)*point(A,0); // first point of 'A'
- // doing everything between start and end
- // create round paths subpath by subpath for every i-th edge
+ // doing everything between start and end
+ // create round paths subpath by subpath for every i-th edge
for(int i=1; i < len; ++i)
- {
+ {
// straight subpath towards i-th edge
LocalPath=point(A,i-1)---point(A,i);
// circle with radius 'R' around i-th edge
@@ -36,23 +36,23 @@ path roundedpath(path A, real R, real S = 1)
// add straight subpath towards i-th curvature to 'RoundPath'
RoundPath=RoundPath--scale(S)*LocalPair;
}
-
+
// straight subpath from i-th edge to (i+1)-th edge
LocalPath=point(A,i)---point(A,i+1);
// calculate intersection-time between straight subpath and circle
real[] t=intersect(LocalPath, LocalCirc);
if(t.length > 0) {
LocalTime=t[0];
- // define intersectionpoint between both paths
+ // define intersectionpoint between both paths
LocalPair=point(subpath(LocalPath, 0, LocalTime), 1);
// add curvature near i-th edge to 'RoundPath'
RoundPath=RoundPath..scale(S)*LocalPair;
}
- }
+ }
- // final steps to have a correct termination
+ // final steps to have a correct termination
if(PathClosed) { // Is 'A' cyclic?
- // straight subpath towards 0-th edge
+ // straight subpath towards 0-th edge
LocalPath=point(A,len-1)---point(A,0);
// circle with radius 'R' around 0-th edge
LocalCirc=circle(point(A,0),R);
@@ -65,15 +65,15 @@ path roundedpath(path A, real R, real S = 1)
// add straight subpath towards 0-th curvature to 'RoundPath'
RoundPath=RoundPath--scale(S)*LocalPair;
}
-
-
+
+
// straight subpath from 0-th edge to 1st edge
LocalPath=point(A,0)---point(A,1);
// calculate intersection-time between straight subpath and circle
real[] t=intersect(LocalPath, LocalCirc);
if(t.length > 0) {
LocalTime=t[0];
- // define intersectionpoint between both paths
+ // define intersectionpoint between both paths
LocalPair=point(subpath(LocalPath, 0, LocalTime), 1);
// add curvature near 0-th edge to 'RoundPath' and close path
RoundPath=RoundPath..scale(S)*LocalPair--cycle;
diff --git a/graphics/asymptote/base/shaders/blend.glsl b/graphics/asymptote/base/shaders/blend.glsl
new file mode 100644
index 0000000000..f3bd26c393
--- /dev/null
+++ b/graphics/asymptote/base/shaders/blend.glsl
@@ -0,0 +1,84 @@
+struct Fragment
+{
+ vec4 color;
+ float depth;
+};
+
+layout(binding=1, std430) buffer offsetBuffer {
+ uint offset[];
+};
+
+layout(binding=2, std430) buffer countBuffer {
+ uint count[];
+};
+
+layout(binding=3, std430) buffer fragmentBuffer {
+ Fragment fragment[];
+};
+
+out vec4 outColor;
+
+uniform uint width;
+uniform vec4 background;
+
+vec4 blend(vec4 outColor, vec4 color)
+{
+ return mix(outColor,color,color.a);
+}
+
+void main()
+{
+ uint headIndex=uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x);
+ uint size=count[headIndex];
+ if(size == 0u) {
+#ifdef GPUINDEXING
+ offset[headIndex]=0u;
+#endif
+ discard;
+ }
+ uint listIndex=offset[headIndex];
+ const uint maxSize=16u;
+
+ // Sort the fragments with respect to descending depth
+ if(size < maxSize) {
+ Fragment sortedList[maxSize];
+
+ sortedList[0]=fragment[listIndex];
+ for(uint i=1u; i < size; i++) {
+ Fragment temp=fragment[listIndex+i];
+ float depth=temp.depth;
+ uint j=i;
+ Fragment f;
+ while(f=sortedList[j-1u], j > 0u && depth > f.depth) {
+ sortedList[j]=f;
+ j--;
+ }
+ sortedList[j]=temp;
+ }
+
+ outColor=background;
+ for(uint i=0u; i < size; i++)
+ outColor=blend(outColor,sortedList[i].color);
+ } else {
+ for(uint i=1u; i < size; i++) {
+ Fragment temp=fragment[listIndex+i];
+ float depth=temp.depth;
+ uint j=i;
+ Fragment f;
+ while(f=fragment[listIndex+j-1u], j > 0u && depth > f.depth) {
+ fragment[listIndex+j]=f;
+ j--;
+ }
+ fragment[listIndex+j]=temp;
+ }
+
+ outColor=background;
+ uint stop=listIndex+size;
+ for(uint i=listIndex; i < stop; i++)
+ outColor=blend(outColor,fragment[i].color);
+ }
+ count[headIndex]=0u;
+#ifdef GPUINDEXING
+ offset[headIndex]=0u;
+#endif
+}
diff --git a/graphics/asymptote/base/shaders/count.glsl b/graphics/asymptote/base/shaders/count.glsl
new file mode 100644
index 0000000000..dae4e51f1b
--- /dev/null
+++ b/graphics/asymptote/base/shaders/count.glsl
@@ -0,0 +1,11 @@
+layout(binding=2, std430) buffer countBuffer {
+ uint count[];
+};
+
+uniform uint width;
+
+void main()
+{
+ atomicAdd(count[uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x)],1u);
+ discard;
+}
diff --git a/graphics/asymptote/base/shaders/count0.glsl b/graphics/asymptote/base/shaders/count0.glsl
new file mode 100644
index 0000000000..9bcb6d222e
--- /dev/null
+++ b/graphics/asymptote/base/shaders/count0.glsl
@@ -0,0 +1,11 @@
+layout(binding=2, std430) buffer countBuffer {
+ uint count[];
+};
+
+uniform uint width;
+
+void main()
+{
+ count[uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x)]=0u;
+ discard;
+}
diff --git a/graphics/asymptote/base/shaders/fragment.glsl b/graphics/asymptote/base/shaders/fragment.glsl
index 057acbc744..423ec679b2 100644
--- a/graphics/asymptote/base/shaders/fragment.glsl
+++ b/graphics/asymptote/base/shaders/fragment.glsl
@@ -10,25 +10,13 @@ struct Light
vec3 color;
};
-uniform int nlights;
+uniform uint nlights;
uniform Light lights[max(Nlights,1)];
uniform MaterialBuffer {
Material Materials[Nmaterials];
};
-#ifdef NORMAL
-#ifndef ORTHOGRAPHIC
-in vec3 ViewPosition;
-#endif
-in vec3 Normal;
-vec3 normal;
-#endif
-
-#ifdef COLOR
-in vec4 Color;
-#endif
-
flat in int materialIndex;
out vec4 outColor;
@@ -38,41 +26,94 @@ vec3 Specular; // Specular tint for nonmetals
float Metallic; // Metallic/Nonmetals parameter
float Fresnel0; // Fresnel at zero for nonmetals
float Roughness2; // roughness squared, for smoothing
+float Roughness;
-#ifdef ENABLE_TEXTURE
-uniform sampler2D environmentMap;
-const float PI=acos(-1.0);
-const float twopi=2*PI;
-const float halfpi=PI/2;
+#ifdef HAVE_SSBO
+struct Fragment
+{
+ vec4 color;
+ float depth;
+};
+
+layout(binding=1, std430) buffer offsetBuffer {
+ uint offset[];
+};
+
+layout(binding=2, std430) buffer countBuffer {
+ uint count[];
+};
+
+layout(binding=3, std430) buffer fragmentBuffer {
+ Fragment fragment[];
+};
+
+uniform uint width;
+#endif
+
+#ifdef NORMAL
+
+#ifndef ORTHOGRAPHIC
+in vec3 ViewPosition;
+#endif
+in vec3 Normal;
+vec3 normal;
-const int numSamples=7;
+#ifdef USE_IBL
+uniform sampler2D reflBRDFSampler;
+uniform sampler2D diffuseSampler;
+uniform sampler3D reflImgSampler;
+
+const float pi=acos(-1.0);
+const float piInv=1.0/pi;
+const float twopi=2.0*pi;
+const float twopiInv=1.0/twopi;
// (x,y,z) -> (r,theta,phi);
-// theta -> [0,\pi]: colatitude
-// phi -> [0, 2\pi]: longitude
+// theta -> [0,pi]: colatitude
+// phi -> [-pi,pi]: longitude
vec3 cart2sphere(vec3 cart)
{
- float x=cart.z;
- float y=cart.x;
+ float x=cart.x;
+ float y=cart.z;
float z=cart.y;
float r=length(cart);
+ float theta=r > 0.0 ? acos(z/r) : 0.0;
float phi=atan(y,x);
- float theta=acos(z/r);
- return vec3(r,phi,theta);
+ return vec3(r,theta,phi);
}
vec2 normalizedAngle(vec3 cartVec)
{
vec3 sphericalVec=cart2sphere(cartVec);
- sphericalVec.y=sphericalVec.y/(2*PI)-0.25;
- sphericalVec.z=sphericalVec.z/PI;
- return sphericalVec.yz;
+ sphericalVec.y=sphericalVec.y*piInv;
+ sphericalVec.z=0.75-sphericalVec.z*twopiInv;
+
+ return sphericalVec.zy;
}
-#endif
-#ifdef NORMAL
+vec3 IBLColor(vec3 viewDir)
+{
+ //
+ // based on the split sum formula approximation
+ // L(v)=\int_\Omega L(l)f(l,v) \cos \theta_l
+ // which, by the split sum approiximation (assuming independence+GGX distrubition),
+ // roughly equals (within a margin of error)
+ // [\int_\Omega L(l)] * [\int_\Omega f(l,v) \cos \theta_l].
+ // the first term is the reflectance irradiance integral
+
+ vec3 IBLDiffuse=Diffuse*texture(diffuseSampler,normalizedAngle(normal)).rgb;
+ vec3 reflectVec=normalize(reflect(-viewDir,normal));
+ vec2 reflCoord=normalizedAngle(reflectVec);
+ vec3 IBLRefl=texture(reflImgSampler,vec3(reflCoord,Roughness)).rgb;
+ vec2 IBLbrdf=texture(reflBRDFSampler,vec2(dot(normal,viewDir),Roughness)).rg;
+ float specularMultiplier=Fresnel0*IBLbrdf.x+IBLbrdf.y;
+ vec3 dielectric=IBLDiffuse+specularMultiplier*IBLRefl;
+ vec3 metal=Diffuse*IBLRefl;
+ return mix(dielectric,metal,Metallic);
+}
+#else
// h is the halfway vector between normal and light direction
// GGX Trowbridge-Reitz Approximation
float NDF_TRG(vec3 h)
@@ -122,18 +163,24 @@ vec3 BRDF(vec3 viewDirection, vec3 lightDirection)
vec3 dielectric=mix(lambertian,rawReflectance*Specular,F);
vec3 metal=rawReflectance*Diffuse;
-
+
return mix(dielectric,metal,Metallic);
}
#endif
+#endif
+
+#ifdef COLOR
+in vec4 Color;
+#endif
+
void main()
{
vec4 diffuse;
vec4 emissive;
Material m;
-#ifdef TRANSPARENT
+#ifdef GENERAL
m=Materials[abs(materialIndex)-1];
emissive=m.emissive;
if(materialIndex >= 0)
@@ -150,18 +197,18 @@ void main()
#ifdef COLOR
diffuse=Color;
#if Nlights == 0
- emissive += Color;
+ emissive += Color;
#endif
-#else
- diffuse=m.diffuse;
+#else
+ diffuse=m.diffuse;
#endif
#endif
-
+
#if defined(NORMAL) && Nlights > 0
Specular=m.specular.rgb;
vec4 parameters=m.parameters;
- Roughness2=1.0-parameters[0];
- Roughness2=Roughness2*Roughness2;
+ Roughness=1.0-parameters[0];
+ Roughness2=Roughness*Roughness;
Metallic=parameters[1];
Fresnel0=parameters[2];
Diffuse=diffuse.rgb;
@@ -178,50 +225,34 @@ void main()
#else
vec3 viewDir=-normalize(ViewPosition);
#endif
+ vec3 color;
+#ifdef USE_IBL
+ color=IBLColor(viewDir);
+#else
// For a finite point light, the rendering equation simplifies.
- vec3 color=emissive.rgb;
- for(int i=0; i < nlights; ++i) {
+ color=emissive.rgb;
+ for(uint i=0u; i < nlights; ++i) {
Light Li=lights[i];
vec3 L=Li.direction;
float cosTheta=max(dot(normal,L),0.0); // $\omega_i \cdot n$ term
vec3 radiance=cosTheta*Li.color;
color += BRDF(viewDir,L)*radiance;
}
-
-#if defined(ENABLE_TEXTURE) && !defined(COLOR)
- // Experimental environment radiance using Riemann sums;
- // can also do importance sampling.
- vec3 envRadiance=vec3(0.0,0.0,0.0);
-
- vec3 normalPerp=vec3(-normal.y,normal.x,0.0);
- if(length(normalPerp) == 0.0)
- normalPerp=vec3(1.0,0.0,0.0);
-
- // we now have a normal basis;
- normalPerp=normalize(normalPerp);
- vec3 normalPerp2=normalize(cross(normal,normalPerp));
-
- const float step=1.0/numSamples;
- const float phistep=twopi*step;
- const float thetastep=halfpi*step;
- for (int iphi=0; iphi < numSamples; ++iphi) {
- float phi=iphi*phistep;
- for (int itheta=0; itheta < numSamples; ++itheta) {
- float theta=itheta*thetastep;
-
- vec3 azimuth=cos(phi)*normalPerp+sin(phi)*normalPerp2;
- vec3 L=sin(theta)*azimuth+cos(theta)*normal;
-
- vec3 rawRadiance=texture(environmentMap,normalizedAngle(L)).rgb;
- vec3 surfRefl=BRDF(Z,L);
- envRadiance += surfRefl*rawRadiance*sin(2.0*theta);
- }
- }
- envRadiance *= halfpi*step*step;
- color += envRadiance.rgb;
#endif
outColor=vec4(color,diffuse.a);
-#else
+#else
outColor=emissive;
-#endif
+#endif
+
+#ifdef HAVE_SSBO
+ uint headIndex=uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x);
+ uint listIndex=offset[headIndex]+atomicAdd(count[headIndex],1u);
+ fragment[listIndex].color=outColor;
+ fragment[listIndex].depth=gl_FragCoord.z;
+#ifdef TRANSPARENT
+#ifndef WIREFRAME
+ discard;
+#endif
+#endif
+#endif
}
diff --git a/graphics/asymptote/base/shaders/offset.glsl b/graphics/asymptote/base/shaders/offset.glsl
new file mode 100644
index 0000000000..5fe24e7558
--- /dev/null
+++ b/graphics/asymptote/base/shaders/offset.glsl
@@ -0,0 +1,11 @@
+layout(binding=1, std430) buffer offsetBuffer {
+ uint offset[];
+};
+
+uniform uint width;
+
+void main()
+{
+ atomicAdd(offset[uint(gl_FragCoord.y)*width+uint(gl_FragCoord.x)+1u],1u);
+ discard;
+}
diff --git a/graphics/asymptote/base/shaders/partialsum.glsl b/graphics/asymptote/base/shaders/partialsum.glsl
new file mode 100644
index 0000000000..0506965c23
--- /dev/null
+++ b/graphics/asymptote/base/shaders/partialsum.glsl
@@ -0,0 +1,54 @@
+layout(local_size_x=PROCESSORS) in;
+
+uniform uint elements;
+uniform uint steps;
+
+layout(binding=0, std430) buffer sumBuffer
+{
+ uint sum[];
+};
+
+layout(binding=1, std430) buffer offsetBuffer
+{
+ uint offset[];
+};
+
+shared uint sharedData[PROCESSORS];
+
+uint ceilquotient(uint a, uint b)
+{
+ return (a+b-1u)/b;
+}
+
+void main(void)
+{
+ uint id=gl_LocalInvocationID.x;
+ sharedData[id]=sum[id];
+
+ barrier();
+
+ uint index=id << 1u;
+ sharedData[index+1u] += sharedData[index];
+ barrier();
+ uint step;
+ for(step=1u; step < steps-1u; step++) {
+ uint mask=(1u << step)-1u;
+ uint index=((id >> step) << (step+1u))+mask;
+ uint windex=index+(id&mask)+1u;
+ sharedData[windex] += sharedData[index];
+ barrier();
+ }
+ uint mask=(1u << step)-1u;
+ index=((id >> step) << steps)+mask;
+ uint windex=index+(id&mask)+1u;
+ if(windex < PROCESSORS)
+ sharedData[windex] += sharedData[index];
+ barrier();
+
+ uint m=ceilquotient(elements,PROCESSORS);
+
+ if(id+1u < PROCESSORS)
+ offset[m*(id+1u)] += sharedData[id];
+ else
+ sum[0]=sharedData[id]; // Store fragment size in sum[0]
+}
diff --git a/graphics/asymptote/base/shaders/postsum.glsl b/graphics/asymptote/base/shaders/postsum.glsl
new file mode 100644
index 0000000000..9a2afaf845
--- /dev/null
+++ b/graphics/asymptote/base/shaders/postsum.glsl
@@ -0,0 +1,30 @@
+layout(local_size_x=1) in;
+
+uniform uint elements;
+
+layout(binding=1, std430) buffer offsetBuffer
+{
+ uint offset[];
+};
+
+uint ceilquotient(uint a, uint b)
+{
+ return (a+b-1u)/b;
+}
+
+void main(void)
+{
+ uint id=gl_GlobalInvocationID.x;
+
+ uint m=ceilquotient(elements,gl_NumWorkGroups.x);
+ uint row=m*id;
+ uint col=min(m,elements-row);
+ uint stop=row+col-1u;
+
+ uint curr=offset[row];
+ for(uint i=row; i < stop; ++i) {
+ uint next=offset[i+1u];
+ curr += next;
+ offset[i+1u]=curr;
+ }
+}
diff --git a/graphics/asymptote/base/shaders/presum.glsl b/graphics/asymptote/base/shaders/presum.glsl
new file mode 100644
index 0000000000..0bcb02c91d
--- /dev/null
+++ b/graphics/asymptote/base/shaders/presum.glsl
@@ -0,0 +1,34 @@
+layout(local_size_x=1) in;
+
+uniform uint elements;
+
+layout(binding=0, std430) buffer sumBuffer
+{
+ uint sum[];
+};
+
+layout(binding=1, std430) buffer offsetBuffer
+{
+ uint offset[];
+};
+
+uint ceilquotient(uint a, uint b)
+{
+ return (a+b-1u)/b;
+}
+
+void main(void)
+{
+ uint id=gl_GlobalInvocationID.x;
+
+ uint m=ceilquotient(elements,gl_NumWorkGroups.x);
+ uint row=m*id;
+ uint col=min(m,elements-row);
+ uint stop=row+col;
+
+ uint Sum=offset[row];
+ for(uint i=row+1u; i < stop; ++i)
+ Sum += offset[i];
+
+ sum[id]=Sum;
+}
diff --git a/graphics/asymptote/base/shaders/screen.glsl b/graphics/asymptote/base/shaders/screen.glsl
new file mode 100644
index 0000000000..9e8611a727
--- /dev/null
+++ b/graphics/asymptote/base/shaders/screen.glsl
@@ -0,0 +1,5 @@
+void main()
+{
+ vec2 vertices[3]=vec2[3](vec2(-1,-1),vec2(3,-1),vec2(-1, 3));
+ gl_Position = vec4(vertices[gl_VertexID],0,1);
+}
diff --git a/graphics/asymptote/base/shaders/vertex.glsl b/graphics/asymptote/base/shaders/vertex.glsl
index 4b2a54b989..42623ccef6 100644
--- a/graphics/asymptote/base/shaders/vertex.glsl
+++ b/graphics/asymptote/base/shaders/vertex.glsl
@@ -1,16 +1,22 @@
in vec3 position;
-uniform mat3 normMat;
-
#ifdef NORMAL
+
#ifndef ORTHOGRAPHIC
+uniform mat4 viewMat;
out vec3 ViewPosition;
#endif
+
+uniform mat3 normMat;
in vec3 normal;
out vec3 Normal;
+
#endif
+#ifdef MATERIAL
in int material;
+flat out int materialIndex;
+#endif
#ifdef COLOR
in vec4 color;
@@ -22,9 +28,6 @@ in float width;
#endif
uniform mat4 projViewMat;
-uniform mat4 viewMat;
-
-flat out int materialIndex;
void main()
{
@@ -45,5 +48,7 @@ void main()
gl_PointSize=width;
#endif
+#ifdef MATERIAL
materialIndex=material;
+#endif
}
diff --git a/graphics/asymptote/base/simplex.asy b/graphics/asymptote/base/simplex.asy
index e6d0410b23..3bc74635db 100644
--- a/graphics/asymptote/base/simplex.asy
+++ b/graphics/asymptote/base/simplex.asy
@@ -219,7 +219,7 @@ struct simplex {
basicValues();
iterate(E,n+k,Bindices);
-
+
if(abs(Em[0]) > EpsilonA) {
case=INFEASIBLE;
return;
@@ -249,7 +249,7 @@ struct simplex {
for(int i=0; i < m; ++i) {
int k=Bindices[i];
if(k > n) continue;
- Bindices[ip]=k;
+ Bindices[ip]=k;
cB[ip]=c[k-1];
real[] Dip=D[ip];
real[] Ei=E[i];
@@ -319,7 +319,7 @@ struct simplex {
ai[j]=Ai[j];
}
}
-
+
int k=0;
bool phase1=false;
diff --git a/graphics/asymptote/base/slide.asy b/graphics/asymptote/base/slide.asy
index 9d26c68065..a695953768 100644
--- a/graphics/asymptote/base/slide.asy
+++ b/graphics/asymptote/base/slide.asy
@@ -32,7 +32,7 @@ real minipagemargin=1inch;
real minipagewidth=pagewidth-2minipagemargin;
transform tinv=inverse(fixedscaling((-1,-1),(1,1),currentpen));
-
+
pen itempen=fontsize(24pt);
pen codepen=fontsize(20pt);
pen titlepagepen=fontsize(36pt);
@@ -55,7 +55,7 @@ real titleskip=0.5;
string oldbulletcolor;
string newbulletcolor="red";
string bullet="{\bulletcolor\textbullet}";
-
+
pair pagenumberposition=S+E;
pair pagenumberalign=4NW;
pen pagenumberpen=fontsize(12);
@@ -90,7 +90,7 @@ bool empty()
return currentpicture.nodes.length <= preamblenodes;
}
-void background()
+void background()
{
if(!background.empty()) {
add(background);
@@ -197,7 +197,7 @@ void nextpage(pen p=pagenumberpen)
firststep=true;
}
-void newslide(bool stepping=true)
+void newslide(bool stepping=true)
{
allowstepping=stepping;
nextpage();
@@ -264,11 +264,11 @@ void outline(string s="Outline", pair position=N, pair align=titlealign,
void remark(bool center=false, string s, pair align=0, pen p=itempen,
real indent=0, bool minipage=true, real skip=itemskip,
- filltype filltype=NoFill, bool step=false)
+ filltype filltype=NoFill, bool step=false)
{
checkposition();
if(minipage) s=minipage(s,minipagewidth);
-
+
pair offset;
if(center) {
if(align == 0) align=S;
@@ -277,12 +277,12 @@ void remark(bool center=false, string s, pair align=0, pen p=itempen,
if(align == 0) align=SE;
offset=currentposition;
}
-
+
frame f;
label(f,s,(indent,0),align,p,filltype);
pair m=tinv*min(f);
pair M=tinv*min(f);
-
+
if(abs(offset.x+M.x) > 1)
warning("slidetoowide","slide too wide on page "+(string) page+':\n'+
(string) s);
@@ -399,7 +399,7 @@ void display(string s, string caption="", pair align=S, pen p=itempen,
display(new string[] {s},caption,align,p,figuremattpen, final);
}
-void figure(string[] s, string options="", real margin=0,
+void figure(string[] s, string options="", real margin=0,
string[] captions=new string[], string caption="",
pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
bool final=true)
@@ -435,7 +435,7 @@ void multifigure(string[] slist, string options="", string caption="",
firststep=false;
}
-void indexedfigure(string prefix, int first, int last,
+void indexedfigure(string prefix, int first, int last,
string options="", string caption="",
pair align=S, pen p=itempen, pen figuremattpen=figuremattpen,
bool step=itemstep)
@@ -473,7 +473,7 @@ string cropcode(string s)
void code(bool center=false, string s, pen p=codepen,
real indent=0, real skip=codeskip,
- filltype filltype=NoFill)
+ filltype filltype=NoFill)
{
remark(center,"{\tt "+verbatim(cropcode(s))+"}",p,indent,skip,filltype);
}
@@ -569,7 +569,7 @@ void bibliographystyle(string name)
texpreamble("\bibliographystyle{"+name+"}");
}
-void bibliography(string name)
+void bibliography(string name)
{
numberpage();
havepagenumber=false;
diff --git a/graphics/asymptote/base/slopefield.asy b/graphics/asymptote/base/slopefield.asy
index e87e2cd36f..c36ee4d9d0 100644
--- a/graphics/asymptote/base/slopefield.asy
+++ b/graphics/asymptote/base/slopefield.asy
@@ -16,7 +16,7 @@ picture slopefield(real f(real,real), pair a, pair b,
pair cp=(x,a.y+j*dy);
real slope=f(cp.x,cp.y);
real mp=step/sqrt(1+slope^2);
- draw(pic,(cp.x-mp,cp.y-mp*slope)--(cp.x+mp,cp.y+mp*slope),p,arrow);
+ draw(pic,(cp.x-mp,cp.y-mp*slope)--(cp.x+mp,cp.y+mp*slope),p,arrow);
}
}
return pic;
@@ -29,12 +29,12 @@ picture slopefield(real f(real), pair a, pair b,
return slopefield(new real(real x, real y) {return f(x);},a,b,nx,ny,p,arrow);
}
-path curve(pair c, real f(real,real), pair a, pair b)
+path curve(pair c, real f(real,real), pair a, pair b)
{
- real step=stepfraction*(b.x-a.x);
+ real step=stepfraction*(b.x-a.x);
real halfstep=0.5*step;
real sixthstep=step/6;
-
+
path follow(real sign) {
pair cp=c;
guide g=cp;
diff --git a/graphics/asymptote/base/smoothcontour3.asy b/graphics/asymptote/base/smoothcontour3.asy
index be6f900a4d..c39d0a3f3d 100644
--- a/graphics/asymptote/base/smoothcontour3.asy
+++ b/graphics/asymptote/base/smoothcontour3.asy
@@ -1,11 +1,11 @@
// Copyright 2015 Charles Staats III
-//
+//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
-//
+//
// http://www.apache.org/licenses/LICENSE-2.0
-//
+//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -72,7 +72,7 @@ patch patchwithnormals(path3 external, triple[] u0normals, triple[] u1normals,
assert(u1normals.length == 3);
assert(v0normals.length == 3);
assert(v1normals.length == 3);
-
+
triple[][] controlpoints = new triple[4][4];
controlpoints[0][0] = point(external,0);
controlpoints[1][0] = postcontrol(external,0);
@@ -217,7 +217,7 @@ patch patchwithnormals(path3 external, triple[] u0normals, triple[] u1normals,
+ "on bezier patch. Using coons patch.");
return patch(external);
}
-
+
for (int i = 1; i <= 2; ++i) {
for (int j = 1; j <= 2; ++j) {
int position = 3 * (2 * (i-1) + (j-1));
@@ -268,7 +268,7 @@ patch trianglewithnormals(path3 external, triple n1,
tangent = dir(external, 2.5);
n3 -= dot(n3,tangent)*tangent;
n3 = unit(n3);
-
+
real wild = 2 * wildnessweight;
real[][] matrix = { {n1.x, n1.y, n1.z},
{n2.x, n2.y, n2.z},
@@ -591,7 +591,7 @@ triple projecttospan(triple toproject, triple v1, triple v2,
path3 pathbetween(path3 edgecycle, int vertex1, int vertex2) {
triple point1 = point(edgecycle, vertex1);
triple point2 = point(edgecycle, vertex2);
-
+
triple v1 = -dir(edgecycle, vertex1, sign=-1);
triple v2 = dir(edgecycle, vertex1, sign= 1);
triple direction1 = projecttospan(unit(point2-point1), v1, v2);
@@ -802,7 +802,7 @@ patch[] triangletoquads(path3 external, real f(triple), triple grad(triple),
return new patch[] {patchwithnormals(quad0, grad),
patchwithnormals(quad1, grad),
- patchwithnormals(quad2, grad)};
+ patchwithnormals(quad2, grad)};
}
// Attempts to fill the path external (which should by a cyclic path consisting of
@@ -837,7 +837,7 @@ patch[] maketriangle(path3 external, real f(triple),
return new patch[] {beziertriangle};
if (!allowsubdivide) return new patch[0];
-
+
positionedvector m1 = positionedvector(m1, n1);
positionedvector m2 = positionedvector(m2, n2);
positionedvector m3 = positionedvector(m3, n3);
@@ -855,7 +855,7 @@ patch[] maketriangle(path3 external, real f(triple),
triangles.append(maketriangle(subpath(external, 0.5, 1.5) & reverse(p12) & cycle,
f, grad=grad, allowsubdivide=false));
if (triangles.length < 3) return new patch[0];
-
+
triangles.append(maketriangle(subpath(external, 1.5, 2.5) & reverse(p23) & cycle,
f, grad=grad, allowsubdivide=false));
if (triangles.length < 4) return new patch[0];
@@ -913,7 +913,7 @@ patch[] quadpatches(path3 edgecycle, positionedvector[] corners,
// The tolerance for considering two points "essentially identical."
static real tolerance = 2.5 * rootfinder_settings.roottolerance;
-
+
// If there are two neighboring vertices that are essentially identical,
// unify them into one.
for (int i = 0; i < corners.length; ++i) {
@@ -948,7 +948,7 @@ patch[] quadpatches(path3 edgecycle, positionedvector[] corners,
return null;
}
}
-
+
if (length(edgecycle) == 3) {
patch[] toreturn = usetriangles ? maketriangle(edgecycle, f, grad)
: triangletoquads(edgecycle, f, grad, a, b);
@@ -961,12 +961,12 @@ patch[] quadpatches(path3 edgecycle, positionedvector[] corners,
int[] bisectorindices;
path3 middleguide = bisector(edgecycle, bisectorindices);
-
+
triple testpoint = point(middleguide, 0.5);
if (!checkpt(testpoint, f, grad, a, b)) {
return null;
}
-
+
patch[] toreturn = null;
path3 firstpatch = subpath(edgecycle, bisectorindices[0], bisectorindices[1])
& reverse(middleguide) & cycle;
@@ -1328,7 +1328,7 @@ struct gridwithzeros {
}
return null;
}
-
+
currentface = XLOW;
nextface = YHIGH;
pushifnonnull(zdirzeros[0][1][0]);
@@ -1393,12 +1393,12 @@ struct gridwithzeros {
if (!checkpt(testpoint, f, grad, corners[0][0][0], corners[1][1][1])) {
return subdividecube();
}
-
+
edgecycle = edgecycle & currentpath;
}
edgecycle = edgecycle & cycle;
-
+
{ // Ensure the outward normals are pointing in the same direction as the gradient.
triple tangentin = patchcorners[0].position - precontrol(edgecycle, 0);
triple tangentout = postcontrol(edgecycle, 0) - patchcorners[0].position;
@@ -1482,7 +1482,7 @@ struct gridwithzeros {
if (k >= nz) reportactive[ZHIGH] = true;
}
}
-
+
for (int i = 0; i < nx+1; ++i) {
for (int j = 0; j < ny+1; ++j) {
for (int k = 0; k < nz+1; ++k) {
@@ -1532,7 +1532,7 @@ struct gridwithzeros {
};
}
-// The external interface of this whole module. Accepts exactly one
+// The external interface of this whole module. Accepts exactly one
// function (throws an error if two or zero functions are specified).
// The function should be differentiable. (Whatever you do, do not
// pass in an indicator function!) Ideally, the zero locus of the
diff --git a/graphics/asymptote/base/solids.asy b/graphics/asymptote/base/solids.asy
index 72110d6f7a..035a00d2fc 100644
--- a/graphics/asymptote/base/solids.asy
+++ b/graphics/asymptote/base/solids.asy
@@ -5,11 +5,11 @@ pen defaultbackpen=linetype(new real[] {4,4},4,scale=false);
// A solid geometry package.
// Try to find a bounding tangent line between two paths.
-real[] tangent(path p, path q, bool side)
+real[] tangent(path p, path q, bool side)
{
static real fuzz=1.0e-5;
- if((cyclic(p) && inside(p,point(q,0)) ||
+ if((cyclic(p) && inside(p,point(q,0)) ||
cyclic(q) && inside(q,point(p,0))) &&
intersect(p,q,fuzz).length == 0) return new real[];
@@ -28,14 +28,14 @@ real[] tangent(path p, path q, bool side)
return new real[];
}
-path line(path p, path q, real[] t)
+path line(path p, path q, real[] t)
{
return point(p,t[0])--point(q,t[1]);
}
// Return the projection of a generalized cylinder of height h constructed
// from area base in the XY plane and aligned with axis.
-path[] cylinder(path3 base, real h, triple axis=Z, projection P)
+path[] cylinder(path3 base, real h, triple axis=Z, projection P)
{
base=rotate(-colatitude(axis),cross(axis,Z))*base;
path3 top=shift(h*axis)*base;
@@ -71,7 +71,7 @@ struct revolution {
triple m;
static real epsilon=10*sqrtEpsilon;
-
+
void operator init(triple c=O, path3 g, triple axis=Z, real angle1=0,
real angle2=360) {
this.c=c;
@@ -82,12 +82,12 @@ struct revolution {
M=max(g);
m=min(g);
}
-
+
revolution copy() {
return revolution(c,g,axis,angle1,angle2);
}
-
+
triple vertex(int i, real j) {
triple v=point(g,i);
triple center=c+dot(v-c,axis)*axis;
@@ -114,7 +114,7 @@ struct revolution {
path3 p=Arc(center,v1,v2,axis,n);
return (angle2-angle1) % 360 == 0 ? p&cycle : p;
}
-
+
// add transverse slice to skeleton s;
void transverse(skeleton s, real t, int n=nslice, projection P) {
skeleton.curve s=s.transverse;
@@ -196,7 +196,7 @@ struct revolution {
int M=(m == 0) ? N : m;
real factor=m == 1 ? 0 : 1/(m-1);
int n=nslice;
-
+
real tfirst=-1;
real tlast;
for(int i=0; i < M; ++i) {
@@ -238,7 +238,7 @@ struct revolution {
G=sfirst.transverse.back[0]..G;
}
}
-
+
skeleton slast;
transverse(slast,tlast,n,P);
if(dot(delta,axis) == 0 || (tlast >= L-epsilon && sign > 0)) {
@@ -287,7 +287,7 @@ struct revolution {
path3 p1=subpath(p,0,t);
path3 p2=subpath(p,t,length(p));
if(length(p1) > 0 &&
- (length(p2) == 0 ||
+ (length(p2) == 0 ||
abs(midpoint(p1)-P.camera) <= abs(midpoint(p2)-P.camera))) {
s.longitudinal.front.push(p1);
s.longitudinal.back.push(p2);
@@ -300,7 +300,7 @@ struct revolution {
push(t1);
push(t2);
}
-
+
skeleton skeleton(int m=0, int n=nslice, projection P) {
skeleton s;
transverse(s,m,n,P);
diff --git a/graphics/asymptote/base/stats.asy b/graphics/asymptote/base/stats.asy
index be9efdfa42..6183fc18df 100644
--- a/graphics/asymptote/base/stats.asy
+++ b/graphics/asymptote/base/stats.asy
@@ -287,6 +287,6 @@ linefit leastsquares(real[] x, real[] y)
real s=sqrt(arg/(n-2));
L.dm=s*sqrt(1/sxx);
L.db=s*sqrt(1+sx^2/sxx)/n;
- }
+ }
return L;
}
diff --git a/graphics/asymptote/base/syzygy.asy b/graphics/asymptote/base/syzygy.asy
index 93889b252e..3cef2b3a75 100644
--- a/graphics/asymptote/base/syzygy.asy
+++ b/graphics/asymptote/base/syzygy.asy
@@ -78,7 +78,7 @@ bp.draw=new guide[] (picture pic, guide[] ins) {
return new guide[] {(centre+offset*NW){NW}..z[0]+h*N,
ins[0]..centre{NE}..z[1]+h*N};
};
-
+
Component bm=new Component;
bm.in=2; bm.out=2;
bm.connections=new int[] {1,0};
@@ -99,7 +99,7 @@ bm.draw=new guide[] (picture pic, guide[] ins) {
return new guide[] {ins[1]..centre{NW}..z[0]+h*N,
(centre+offset*NE){NE}..z[1]+h*N};
};
-
+
Component phi=new Component;
phi.in=2; phi.out=1;
phi.connections=new int[] {0,0};
@@ -442,7 +442,7 @@ struct Braid { // {{{1
p.place + p.c.in <= place ? 0 : // The string doesn't touch it.
place-p.place+2;*/
}
-
+
int[] pullbackWindow(int step, int w_place, int w_size) {
int[] a={1};
for (int place=0; place<n; ++place)
@@ -735,7 +735,7 @@ struct Syzygy { // {{{1
bool showall=false;
bool number=false; // Number the diagrams when drawn.
- string lsym, codename;
+ string lsym, codename;
bool watched=false;
bool uptodate=true;
diff --git a/graphics/asymptote/base/three.asy b/graphics/asymptote/base/three.asy
index 5fc0d2f109..fbca4b3960 100644
--- a/graphics/asymptote/base/three.asy
+++ b/graphics/asymptote/base/three.asy
@@ -1,8 +1,5 @@
private import math;
-if(settings.xasy)
- settings.render=0;
-
if(prc0()) {
if(!latex()) settings.prc=false;
else {
@@ -11,8 +8,9 @@ if(prc0()) {
}
}
-// Useful lossy compression values.
+// Useful lossy PRC compression values.
restricted real Zero=0;
+restricted real Single=0.000001;
restricted real Low=0.0001;
restricted real Medium=0.001;
restricted real High=0.01;
@@ -20,6 +18,27 @@ restricted real High=0.01;
restricted int PRCsphere=0; // Renders slowly but produces smaller PRC files.
restricted int NURBSsphere=1; // Renders fast but produces larger PRC files.
+struct interaction
+{
+ int type;
+ triple center; // position to rotate billboard objects about
+ bool targetsize;
+ static interaction defaultinteraction;
+
+ void operator init(interaction interaction=defaultinteraction,
+ int type=interaction.type,
+ triple center=interaction.center, bool targetsize=interaction.targetsize) {
+ this.type=type;
+ this.center=center;
+ this.targetsize=targetsize;
+ }
+}
+
+interaction.defaultinteraction=new interaction;
+
+restricted interaction Embedded=interaction();
+restricted interaction Billboard=interaction(1);
+
struct render
{
// PRC parameters:
@@ -41,19 +60,22 @@ struct render
bool partnames; // assign part name indices to compound objects
bool defaultnames; // assign default names to unnamed objects
+ interaction interaction; // billboard interaction mode
static render defaultrender;
-
- void operator init(real compression=defaultrender.compression,
- real granularity=defaultrender.granularity,
- bool closed=defaultrender.closed,
- bool tessellate=defaultrender.tessellate,
- bool3 merge=defaultrender.merge,
- int sphere=defaultrender.sphere,
- real margin=defaultrender.margin,
- bool labelfill=defaultrender.labelfill,
- bool partnames=defaultrender.partnames,
- bool defaultnames=defaultrender.defaultnames)
+
+ void operator init(render render=defaultrender,
+ real compression=render.compression,
+ real granularity=render.granularity,
+ bool closed=render.closed,
+ bool tessellate=render.tessellate,
+ bool3 merge=render.merge,
+ int sphere=render.sphere,
+ real margin=render.margin,
+ bool labelfill=render.labelfill,
+ bool partnames=render.partnames,
+ bool defaultnames=render.defaultnames,
+ interaction interaction=render.interaction)
{
this.compression=compression;
this.granularity=granularity;
@@ -65,6 +87,7 @@ struct render
this.labelfill=labelfill;
this.partnames=partnames;
this.defaultnames=defaultnames;
+ this.interaction=interaction;
}
}
@@ -81,6 +104,7 @@ defaultrender.sphere=NURBSsphere;
defaultrender.labelfill=true;
defaultrender.partnames=false;
defaultrender.defaultnames=true;
+defaultrender.interaction=Embedded;
real defaultshininess=0.7;
real defaultmetallic=0.0;
@@ -95,7 +119,7 @@ string defaultembed3Doptions="3Dmenu";
string defaultembed3Dscript;
real defaulteyetoview=63mm/1000mm;
-string partname(int i, render render=defaultrender)
+string partname(int i, render render=defaultrender)
{
return render.partnames ? string(i+1) : "";
}
@@ -158,8 +182,8 @@ transform3 scale(triple v, real s)
v=unit(v);
s -= 1;
return new real[][] {
- {1+s*v.x^2, s*v.x*v.y, s*v.x*v.z, 0},
- {s*v.x*v.y, 1+s*v.y^2, s*v.y*v.z, 0},
+ {1+s*v.x^2, s*v.x*v.y, s*v.x*v.z, 0},
+ {s*v.x*v.y, 1+s*v.y^2, s*v.y*v.z, 0},
{s*v.x*v.z, s*v.y*v.z, 1+s*v.z^2, 0},
{0, 0, 0, 1}};
}
@@ -248,7 +272,7 @@ transform3 look(triple eye, triple up=Z, triple target=O)
}
// Return a matrix to do perspective distortion based on a triple v.
-transform3 distort(triple v)
+transform3 distort(triple v)
{
transform3 t=identity(4);
real d=length(v);
@@ -410,7 +434,7 @@ projection TopView=orthographic(Z,up=Y,showtarget=true);
currentprojection=perspective(5,4,2);
-projection projection()
+projection projection()
{
projection P;
real[] a=_projection();
@@ -467,8 +491,8 @@ struct control {
}
control nocontrol;
-
-control operator * (transform3 t, control c)
+
+control operator * (transform3 t, control c)
{
control C;
C.post=t*c.post;
@@ -485,7 +509,7 @@ void write(file file, control c)
write(file," and ");
write(file,c.pre);
}
-
+
struct Tension {
real out,in;
bool atLeast;
@@ -510,7 +534,7 @@ Tension operator init()
Tension noTension;
noTension.active=false;
-
+
void write(file file, Tension t)
{
write(file,"..tension ");
@@ -519,7 +543,7 @@ void write(file file, Tension t)
write(file," and ");
write(file,t.in);
}
-
+
struct dir {
triple dir;
real gamma=1; // endpoint curl
@@ -561,8 +585,8 @@ void write(file file, dir d)
write(file,"{curl "); write(file,d.gamma); write(file,"}");
}
}
-
-dir operator * (transform3 t, dir d)
+
+dir operator * (transform3 t, dir d)
{
dir D=d.copy();
D.init(unit(shiftless(t)*d.dir));
@@ -596,11 +620,11 @@ struct flatguide3 {
bool cyclic() {int n=cyclic.length; return n > 0 ? cyclic[n-1] : false;}
bool precyclic() {int i=find(cyclic); return i >= 0 && i < cyclic.length-1;}
-
+
int size() {
return cyclic() ? nodes.length-1 : nodes.length;
}
-
+
void node(triple v, bool b=false) {
nodes.push(v);
control.push(nocontrol);
@@ -650,7 +674,7 @@ struct flatguide3 {
if(nodes.length > 0)
node(nodes[0],true);
}
-
+
// Return true if outgoing direction at node i is known.
bool solved(int i) {
return out[i].active() || control[i].active;
@@ -705,13 +729,13 @@ guide3 operator cast(cycleToken) {
};
}
-guide3 operator controls(triple post, triple pre)
+guide3 operator controls(triple post, triple pre)
{
return new void(flatguide3 f) {
f.control(post,pre);
};
};
-
+
guide3 operator controls(triple v)
{
return operator controls(v,v);
@@ -743,7 +767,7 @@ guide3 operator spec(triple v, int side)
abort("invalid direction specifier");
};
}
-
+
guide3 operator -- (... guide3[] g)
{
return new void(flatguide3 f) {
@@ -805,13 +829,13 @@ real asin1(real x)
{
return asin(min(max(x,-1),1));
}
-
+
// A version of acos that tolerates numerical imprecision
real acos1(real x)
{
return acos(min(max(x,-1),1));
}
-
+
struct Controls {
triple c0,c1;
@@ -840,7 +864,7 @@ private triple cross(triple d0, triple d1, triple reference)
triple normal=cross(d0,d1);
return normal == O ? reference : normal;
}
-
+
private triple dir(real theta, triple d0, triple d1, triple reference)
{
triple normal=cross(d0,d1,reference);
@@ -860,7 +884,7 @@ private real angle(triple d0, triple d1, triple reference)
// beta[i] is the tension for segment i, and in[i] is the incoming
// direction for segment i (where segment i begins at node i).
-real[] theta(triple[] v, real[] alpha, real[] beta,
+real[] theta(triple[] v, real[] alpha, real[] beta,
triple dir0, triple dirn, real g0, real gn, triple reference)
{
real[] a,b,c,f,l,psi;
@@ -905,7 +929,7 @@ real[] theta(triple[] v, real[] alpha, real[] beta,
f[n]=angle(v[n]-v[n-1],dirn,reference);
}
}
-
+
for(int i=i0; i < n; ++i) {
real in=beta[i-1]^2*l[i-1];
real A=in/alpha[i-1];
@@ -917,14 +941,14 @@ real[] theta(triple[] v, real[] alpha, real[] beta,
c[i]=C;
f[i]=-B*psi[i-1]-C*psi[i];
}
-
+
return tridiagonal(a,b,c,f);
}
triple reference(triple[] v, int n, triple d0, triple d1)
{
triple[] V=sequence(new triple(int i) {
- return cross(v[i+1]-v[i],v[i+2]-v[i+1]);
+ return cross(v[i+1]-v[i],v[i+2]-v[i+1]);
},n-1);
if(n > 0) {
V.push(cross(d0,v[1]-v[0]));
@@ -952,18 +976,18 @@ triple reference(triple[] v, int n, triple d0, triple d1)
}
// Fill in missing directions for n cyclic nodes.
-void aim(flatguide3 g, int N)
+void aim(flatguide3 g, int N)
{
bool cyclic=true;
int start=0, end=0;
-
+
// If the cycle contains one or more direction specifiers, break the loop.
for(int k=0; k < N; ++k)
if(g.solved(k)) {cyclic=false; end=k; break;}
for(int k=N-1; k >= 0; --k)
if(g.solved(k)) {cyclic=false; start=k; break;}
while(start < N && g.control[start].active) ++start;
-
+
int n=N-(start-end);
if(n <= 1 || (cyclic && n <= 2)) return;
@@ -993,7 +1017,7 @@ void aim(flatguide3 g, int N)
v.cyclic=true;
theta.cyclic=true;
-
+
for(int k=1; k < (cyclic ? n+1 : n); ++k) {
triple w=dir(theta[k],v[k]-v[k-1],v[k+1]-v[k],reference);
g.in[(start+k-1) % N].init(w);
@@ -1008,7 +1032,7 @@ void aim(flatguide3 g, int N)
}
// Fill in missing directions for the sequence of nodes i...n.
-void aim(flatguide3 g, int i, int n)
+void aim(flatguide3 g, int i, int n)
{
int j=n-i;
if(j > 1 || g.out[i].dir != O || g.in[i].dir != O) {
@@ -1021,7 +1045,7 @@ void aim(flatguide3 g, int i, int n)
beta[k]=g.Tension[i+k].in;
}
v[j]=g.nodes[n];
-
+
triple d0=g.out[i].dir;
triple d1=g.in[n-1].dir;
@@ -1029,7 +1053,7 @@ void aim(flatguide3 g, int i, int n)
real[] theta=theta(v,alpha,beta,d0,d1,g.out[i].gamma,g.in[n-1].gamma,
reference);
-
+
for(int k=1; k < j; ++k) {
triple w=dir(theta[k],v[k]-v[k-1],v[k+1]-v[k],reference);
g.in[i+k-1].init(w);
@@ -1175,7 +1199,7 @@ path path(path3 p, pair P(triple)=xypart)
for(int i=1; i < n; ++i)
g=straight(p,i-1) ? g--P(point(p,i)) :
g..controls P(postcontrol(p,i-1)) and P(precontrol(p,i))..P(point(p,i));
-
+
if(straight(p,n-1))
return cyclic(p) ? g--cycle : g--P(point(p,n));
@@ -1241,16 +1265,16 @@ path3 solve(flatguide3 g)
for(int i=0; i < n; ++i) {
if(g.nodes[i] == g.nodes[i+1] && !g.control[i].active)
g.control[i]=control(g.nodes[i],g.nodes[i],straight=true);
- }
-
+ }
+
// Fill in empty direction specifiers inherited from explicit control points.
for(int i=0; i < n; ++i) {
if(g.control[i].active) {
g.out[i].init(g.control[i].post-g.nodes[i]);
g.in[i].init(g.nodes[i+1]-g.control[i].pre);
}
- }
-
+ }
+
// Propagate directions across nodes.
for(int i=0; i < n; ++i) {
int next=g.cyclic[i+1] ? 0 : i+1;
@@ -1260,8 +1284,8 @@ path3 solve(flatguide3 g)
g.out[next].default(g.in[i]);
g.out[i+1].default(g.in[i]);
}
- }
-
+ }
+
// Compute missing 3D directions.
// First, resolve cycles
int i=find(g.cyclic);
@@ -1278,7 +1302,7 @@ path3 solve(flatguide3 g)
}
}
}
-
+
// Next, resolve sequences.
int i=0;
int start=0;
@@ -1288,13 +1312,13 @@ path3 solve(flatguide3 g)
if(i > n) break;
// Look for the end of the sequence.
while(i < n && !g.solved(i)) ++i;
-
+
while(start < i && g.control[start].active) ++start;
-
- if(start < i)
+
+ if(start < i)
aim(g,start,i);
}
-
+
// Compute missing 3D control points.
for(int i=0; i < n; ++i) {
int next=g.cyclic[i+1] ? 0 : i+1;
@@ -1344,7 +1368,7 @@ path3 solve(flatguide3 g)
straight[n-1]=false;
}
}
-
+
return path3(pre,point,post,straight,cyclic);
}
@@ -1385,7 +1409,7 @@ path project(path3 p, projection P=currentprojection,
int last=length(p);
if(last < 0) return g;
-
+
transform3 t=P.t;
if(ninterpolate == 1 || piecewisestraight(p)) {
@@ -1401,7 +1425,7 @@ path project(path3 p, projection P=currentprojection,
}
}
} else return nurb(p,P);
-
+
if(cyclic(p))
g=straight(p,last-1) ? g--cycle :
g..controls project(postcontrol(p,last-1),t) and
@@ -1418,11 +1442,11 @@ path[] project(explicit path3[] g, projection P=currentprojection)
{
return sequence(new path(int i) {return project(g[i],P);},g.length);
}
-
+
guide3 operator cast(path3 p)
{
int last=length(p);
-
+
bool cyclic=cyclic(p);
int stop=cyclic ? last-1 : last;
return new void(flatguide3 f) {
@@ -1456,7 +1480,7 @@ triple normal(path3 p)
real fuzz=sqrtEpsilon*abs(max(p)-min(p));
real absnormal;
real theta;
-
+
bool Cross(triple a, triple b) {
if(abs(a) >= fuzz && abs(b) >= fuzz) {
triple n=cross(unit(a),unit(b));
@@ -1478,7 +1502,7 @@ triple normal(path3 p)
}
return false;
}
-
+
int L=length(p);
if(L <= 0) return O;
@@ -1505,7 +1529,7 @@ triple normal(triple[] p)
real fuzz=sqrtEpsilon*abs(maxbound(p)-minbound(p));
real absnormal;
real theta;
-
+
bool Cross(triple a, triple b) {
if(abs(a) >= fuzz && abs(b) >= fuzz) {
triple n=cross(unit(a),unit(b));
@@ -1526,7 +1550,7 @@ triple normal(triple[] p)
}
return false;
}
-
+
if(p.length <= 0) return O;
triple zi=p[0];
@@ -1642,7 +1666,7 @@ Label project(Label L, triple u, triple v, triple O=O,
projection P=currentprojection) {
Label L=L.copy();
L.position=project(O,P.t);
- L.transform(transform(u,v,O,P));
+ L.transform(transform(u,v,O,P));
return L;
}
@@ -1674,7 +1698,7 @@ void write(file file, string s="", explicit guide3[] x, suffix suffix=none)
write(file,s,(path3[]) x,suffix);
}
-void write(string s="", explicit guide3[] x, suffix suffix=endl)
+void write(string s="", explicit guide3[] x, suffix suffix=endl)
{
write(stdout,s,(path3[]) x,suffix);
}
@@ -1850,7 +1874,7 @@ real relative(Label L, path3 g)
}
// return the linear transformation that maps X,Y,Z to u,v,w.
-transform3 transform3(triple u, triple v, triple w=cross(u,v))
+transform3 transform3(triple u, triple v, triple w=cross(u,v))
{
return new real[][] {
{u.x,v.x,w.x,0},
@@ -1915,37 +1939,37 @@ path3[] operator cast(guide3 g)
return new path3[] {(path3) g};
}
-path3[] operator ^^ (path3 p, path3 q)
+path3[] operator ^^ (path3 p, path3 q)
{
return new path3[] {p,q};
}
-path3[] operator ^^ (path3 p, explicit path3[] q)
+path3[] operator ^^ (path3 p, explicit path3[] q)
{
return concat(new path3[] {p},q);
}
-path3[] operator ^^ (explicit path3[] p, path3 q)
+path3[] operator ^^ (explicit path3[] p, path3 q)
{
return concat(p,new path3[] {q});
}
-path3[] operator ^^ (explicit path3[] p, explicit path3[] q)
+path3[] operator ^^ (explicit path3[] p, explicit path3[] q)
{
return concat(p,q);
}
-path3[] operator * (transform3 t, explicit path3[] p)
+path3[] operator * (transform3 t, explicit path3[] p)
{
return sequence(new path3(int i) {return t*p[i];},p.length);
}
-triple[] operator * (transform3 t, triple[] v)
+triple[] operator * (transform3 t, triple[] v)
{
return sequence(new triple(int i) {return t*v[i];},v.length);
}
-triple[][] operator * (transform3 t, triple[][] v)
+triple[][] operator * (transform3 t, triple[][] v)
{
triple[][] V=new triple[v.length][];
for(int i=0; i < v.length; ++i) {
@@ -1979,7 +2003,7 @@ path3 randompath3(int n, bool cumulate=true, interpolate3 join=operator ..)
triple w;
for(int i=0; i <= n; ++i) {
triple z=(unitrand()-0.5,unitrand()-0.5,unitrand()-0.5);
- if(cumulate) w += z;
+ if(cumulate) w += z;
else w=z;
g=join(g,w);
}
@@ -2040,15 +2064,15 @@ path3 arc(triple c, triple v1, triple v2, triple normal=O, bool direction=CCW)
v1=Tinv*v1;
v2=Tinv*v2;
}
-
+
string invalidnormal="invalid normal vector";
real fuzz=sqrtEpsilon;
if(abs(v1.z) > fuzz || abs(v2.z) > fuzz)
abort(invalidnormal);
-
+
real[] t1=intersect(unitcircle3,O--2*(v1.x,v1.y,0));
real[] t2=intersect(unitcircle3,O--2*(v2.x,v2.y,0));
-
+
if(t1.length == 0 || t2.length == 0)
abort(invalidnormal);
@@ -2102,21 +2126,19 @@ void draw(frame f, path3 g, material p=currentpen, light light=nolight,
string name="", render render=defaultrender,
projection P=currentprojection);
-void begingroup3(frame f, string name="", render render=defaultrender,
- triple center=O, int interaction=0)
+void begingroup3(frame f, string name="", render render=defaultrender)
{
_begingroup3(f,name,render.compression,render.granularity,render.closed,
render.tessellate,render.merge == false,
- render.merge == true,center,interaction);
+ render.merge == true,render.interaction.center,render.interaction.type);
}
void begingroup3(picture pic=currentpicture, string name="",
- render render=defaultrender,
- triple center=O, int interaction=0)
+ render render=defaultrender)
{
pic.add(new void(frame f, transform3, picture pic, projection) {
if(is3D())
- begingroup3(f,name,render,center,interaction);
+ begingroup3(f,name,render);
if(pic != null)
begingroup(pic);
},true);
@@ -2141,7 +2163,7 @@ void addPath(picture pic, path3 g, pen p)
include three_surface;
include three_margins;
-pair min(path3 p, projection P)
+pair min(path3 p, projection P)
{
path3 q=P.T.modelview*p;
if(P.infinity)
@@ -2149,7 +2171,7 @@ pair min(path3 p, projection P)
return maxratio(q)/P.T.projection[3][2];
}
-pair max(path3 p, projection P)
+pair max(path3 p, projection P)
{
path3 q=P.T.modelview*p;
if(P.infinity)
@@ -2157,7 +2179,7 @@ pair max(path3 p, projection P)
return minratio(q)/P.T.projection[3][2];
}
-pair min(frame f, projection P)
+pair min(frame f, projection P)
{
frame g=P.T.modelview*f;
if(P.infinity)
@@ -2165,7 +2187,7 @@ pair min(frame f, projection P)
return maxratio(g)/P.T.projection[3][2];
}
-pair max(frame f, projection P)
+pair max(frame f, projection P)
{
frame g=P.T.modelview*f;
if(P.infinity)
@@ -2210,7 +2232,7 @@ draw=new void(frame f, path3 g, material p=currentpen,
void drawthick(path3 g) {
if(settings.thick && width > 0) {
bool prc=prc();
- bool webgl=settings.outformat == "html";
+ bool primitive=primitive();
real linecap=linecap(q);
real r=0.5*width;
bool open=!cyclic(g);
@@ -2256,7 +2278,7 @@ draw=new void(frame f, path3 g, material p=currentpen,
}
}
// Draw central core for better small-scale rendering.
- if((!prc || piecewisestraight(g)) && !webgl && opacity(q) == 1)
+ if((!prc || piecewisestraight(g)) && !primitive && opacity(q) == 1)
_draw(f,c,p,light);
}
for(surface s : T.s)
@@ -2319,7 +2341,7 @@ void draw(picture pic=currentpicture, explicit path3[] g,
include three_arrows;
-void draw(picture pic=currentpicture, Label L="", path3 g,
+void draw(picture pic=currentpicture, Label L="", path3 g,
align align=NoAlign, material p=currentpen, arrowbar3 arrow,
arrowbar3 bar=None, margin3 margin=NoMargin3, light light=nolight,
light arrowheadlight=currentlight, string name="",
@@ -2409,12 +2431,12 @@ triple min3(picture pic, projection P=currentprojection)
{
return pic.min3(P);
}
-
+
triple max3(picture pic, projection P=currentprojection)
{
return pic.max3(P);
}
-
+
triple size3(picture pic, bool user=false, projection P=currentprojection)
{
transform3 t=pic.calculateTransform3(P);
@@ -2635,7 +2657,7 @@ struct scene
transform3 T=identity4;
picture pic2;
bool keepAspect=true;
-
+
void operator init(frame f, real width, real height,
projection P=currentprojection) {
this.f=f;
@@ -2644,14 +2666,14 @@ struct scene
this.width=width;
this.height=height;
}
-
+
void operator init(picture pic, real xsize=pic.xsize, real ysize=pic.ysize,
bool keepAspect=pic.keepAspect, bool is3D=true,
projection P=currentprojection) {
real xsize3=pic.xsize3, ysize3=pic.ysize3, zsize3=pic.zsize3;
bool warn=true;
this.keepAspect=keepAspect;
-
+
if(xsize3 == 0 && ysize3 == 0 && zsize3 == 0) {
xsize3=ysize3=zsize3=max(xsize,ysize);
warn=false;
@@ -2787,6 +2809,7 @@ object embed(string prefix=outprefix(), string label=prefix,
triple orthoshift;
modelview=P.T.modelview;
transform3 inv;
+ bool prc=prc(format);
if(P.absolute) {
Q=modelview*P;
inv=inverse(modelview);
@@ -2798,12 +2821,13 @@ object embed(string prefix=outprefix(), string label=prefix,
if(Q.t[2][3] == -1) // PRC can't handle oblique projections
Q=orthographic(P.camera,P.up,P.target,P.zoom,P.viewportshift,
- P.showtarget,P.center);
+ P.showtarget,P.center);
+
if(P.infinity) {
triple m=min3(S.f);
triple M=max3(S.f);
triple lambda=M-m;
- if(S.keepAspect) {
+ if(S.keepAspect || prc) {
S.viewportmargin=viewportmargin((lambda.x,lambda.y));
S.width=ceil(lambda.x+2*S.viewportmargin.x);
S.height=ceil(lambda.y+2*S.viewportmargin.y);
@@ -2821,7 +2845,7 @@ object embed(string prefix=outprefix(), string label=prefix,
inv=inverse(modelview);
Q.angle=P.angle;
if(settings.verbose > 0) {
- if(S.adjusted)
+ if(S.adjusted)
write("adjusting camera to ",tinv*inv*P.camera);
target=inv*P.target;
}
@@ -2835,7 +2859,6 @@ object embed(string prefix=outprefix(), string label=prefix,
light Light=modelview*light;
if(prefix == "") prefix=outprefix();
- bool prc=prc(format);
bool preview=settings.render > 0 && !prconly();
if(prc) {
// The media9.sty package cannot handle spaces or dots in filenames.
@@ -2868,12 +2891,12 @@ object embed(string prefix=outprefix(), string label=prefix,
if(P.infinity) {
triple margin=(S.viewportmargin.x,S.viewportmargin.y,0);
- M += margin;
+ M += margin;
m -= margin;
} else if(M.z >= 0) abort("camera too close");
- if(settings.outformat == "html")
- format="html";
+ if(primitive())
+ format=settings.outformat;
shipout3(prefix,f,preview ? nativeformat() : format,
S.width-defaultrender.margin,S.height-defaultrender.margin,
@@ -2893,7 +2916,7 @@ object embed(string prefix=outprefix(), string label=prefix,
transform T=S.pic2.scaling(S.width,S.height);
_shipout(image,S.pic2.fit(T),newframe,nativeformat(),false,false);
}
-
+
image += "."+nativeformat();
if(!settings.inlinetex) file3.push(image);
image=graphic(image,"hiresbb");
@@ -2924,7 +2947,7 @@ shift");
if(P.infinity) {
triple lambda=max3(S.f)-min3(S.f);
pair margin=viewportmargin((lambda.x,lambda.y));
- viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/(Q.zoom);
+ viewplanesize=(max(lambda.x+2*margin.x,lambda.y+2*margin.y))/Q.zoom;
transform3 t=inv*shift(-orthoshift);
Q=t*Q;
S.f=t*S.f;
@@ -2948,7 +2971,7 @@ object embed(string prefix=outprefix(), string label=prefix,
{
bool is3D=is3D(format);
scene S=scene(pic,xsize,ysize,keepAspect,is3D,P);
- if(is3D)
+ if(is3D && !(settings.xasy && format == ""))
return embed(prefix,label,text,S,format,view,options,script,light);
else {
object F;
@@ -3017,7 +3040,9 @@ currentpicture.fitter=new frame(string prefix, picture pic, string format,
return embed(prefix=prefix,pic,format,xsize,ysize,keepAspect,view,
options,script,light,P);
},prefix,format,view,light);
- if(is3D(format) || empty3) add(f,pic.fit2(xsize,ysize,keepAspect));
+
+ if(is3D(format) || empty3)
+ add(f,pic.fit2(xsize,ysize,keepAspect));
return f;
};
@@ -3056,7 +3081,7 @@ void addViews(picture dest, picture src, projection[][] views=SixViewsUS,
frame[][] F=array(views.length,new frame[]);
pair[][] M=array(views.length,new pair[]);
pair[][] m=array(views.length,new pair[]);
-
+
for(int i=0; i < views.length; ++i) {
projection[] viewsi=views[i];
frame[] Fi=F[i];
@@ -3076,17 +3101,17 @@ void addViews(picture dest, picture src, projection[][] views=SixViewsUS,
}
}
}
-
+
real[] my=new real[views.length];
real[] My=new real[views.length];
-
+
int Nj=0;
for(int i=0; i < views.length; ++i) {
my[i]=minbound(m[i]).y;
My[i]=maxbound(M[i]).y;
Nj=max(Nj,views[i].length);
}
-
+
real[] mx=array(Nj,infinity);
real[] Mx=array(Nj,-infinity);
for(int i=0; i < views.length; ++i) {
@@ -3179,10 +3204,10 @@ frame[] fit3(string prefix="", picture[] pictures, picture all,
frame f=embedder(prefix,out[i],format,S.width,S.height,view,options,
script,light,S.P);
if(!settings.loop) out[i]=f;
- }
+ }
if(!settings.loop) break;
}
-
+
settings.animating=false;
settings.interrupt=false;
settings.reverse=reverse;
diff --git a/graphics/asymptote/base/three_arrows.asy b/graphics/asymptote/base/three_arrows.asy
index b0369e6bea..35f6bc4cea 100644
--- a/graphics/asymptote/base/three_arrows.asy
+++ b/graphics/asymptote/base/three_arrows.asy
@@ -37,7 +37,7 @@ triple bend(triple p, path3 g, real scale)
return bend(g,arctime(g,arclength(g)+p.z-scale))*(p.x,p.y,0);
}
-void bend(surface s, path3 g, real L)
+void bend(surface s, path3 g, real L)
{
for(patch p : s.s) {
for(int i=0; i < 4; ++i) {
@@ -140,7 +140,7 @@ DefaultHead3.head=new surface(path3 g, position position=EndPoint,
path3 r=subpath(g,position,0);
path3 s=subpath(r,arctime(r,size),0);
- int n=length(s);
+ int n=length(s);
bool straight1=n == 1 && straight(g,0);
real aspect=Tan(angle);
real width=size*aspect;
@@ -186,7 +186,7 @@ arrowhead3 HookHead3(real dir=arrowdir, real barb=arrowbarb)
filltype filltype=null, bool forwards=true,
projection P=currentprojection) {
if(size == 0) size=a.size(p);
-
+
bool relative=position.relative;
real position=position.position.x;
if(relative) position=reltime(g,position);
@@ -198,7 +198,7 @@ arrowhead3 HookHead3(real dir=arrowdir, real barb=arrowbarb)
YZplane);
surface head=surface(O,reverse(approach(subpath(H,1,0),7,1.5))&
approach(subpath(H,1,2),4,2),Z);
-
+
if(straight1) {
triple v=point(s,0);
triple u=point(s,1)-v;
@@ -324,7 +324,7 @@ private real position(position position, real size, path3 g, bool center)
position *= arclength(g);
if(center) position += 0.5*size;
position=arctime(g,position);
- } else if(center)
+ } else if(center)
position=arctime(g,arclength(subpath(g,0,position))+0.5*size);
return position;
}
@@ -450,7 +450,7 @@ picture arrow2(arrowhead3 arrowhead=DefaultHead3,
path3 g, material p=currentpen, material arrowheadpen=p,
real size=0, real angle=arrowangle, filltype filltype=null,
margin3 margin=NoMargin3, light light=nolight,
- light arrowheadlight=currentlight)
+ light arrowheadlight=currentlight)
{
pen q=(pen) p;
if(size == 0) size=arrowhead.size(q);
@@ -539,7 +539,7 @@ void bar(picture pic, triple a, triple d, triple perp=O,
pic.addPoint(a,v-M);
pic.addPoint(a,v+M);
}
-
+
picture bar(triple a, triple dir, triple perp=O, material p=currentpen)
{
picture pic;
@@ -620,11 +620,11 @@ arrowbar3 BeginArcArrow3(arrowhead3 arrowhead=DefaultHead3,
material arrowheadpen=nullpen)
{
return new bool(picture pic, path3 g, material p, margin3 margin,
- light light, light arrowheadlight) {
+ light light, light arrowheadlight) {
real size=size == 0 ? arrowhead.arcsize((pen) p) : size;
add(pic,arrowhead,size,angle,filltype,position,arrowheadpen,g,p,
forwards=false,margin,light,arrowheadlight);
- return false;
+ return false;
};
}
@@ -685,7 +685,7 @@ arrowbar3 BeginBar3(real size=0, triple dir=O)
};
}
-arrowbar3 Bar3(real size=0, triple dir=O)
+arrowbar3 Bar3(real size=0, triple dir=O)
{
return new bool(picture pic, path3 g, material p, margin3 margin, light light,
light) {
@@ -696,9 +696,9 @@ arrowbar3 Bar3(real size=0, triple dir=O)
};
}
-arrowbar3 EndBar3(real size=0, triple dir=O)=Bar3;
+arrowbar3 EndBar3(real size=0, triple dir=O)=Bar3;
-arrowbar3 Bars3(real size=0, triple dir=O)
+arrowbar3 Bars3(real size=0, triple dir=O)
{
return new bool(picture pic, path3 g, material p, margin3 margin, light light,
light) {
diff --git a/graphics/asymptote/base/three_light.asy b/graphics/asymptote/base/three_light.asy
index 46b0fef7d0..f17a4324c9 100644
--- a/graphics/asymptote/base/three_light.asy
+++ b/graphics/asymptote/base/three_light.asy
@@ -1,7 +1,7 @@
struct material {
pen[] p; // diffusepen,emissivepen,specularpen
real opacity;
- real shininess;
+ real shininess;
real metallic;
real fresnel0; // Reflectance rate at a perfect normal angle.
@@ -34,7 +34,7 @@ struct material {
void specular(pen q) {p[2]=q;}
}
-material operator init()
+material operator init()
{
return material();
}
@@ -57,7 +57,7 @@ void write(string s="", material x, suffix suffix=endl)
{
write(stdout,s,x,suffix);
}
-
+
bool operator == (material m, material n)
{
return all(m.p == n.p) && m.opacity == n.opacity &&
diff --git a/graphics/asymptote/base/three_margins.asy b/graphics/asymptote/base/three_margins.asy
index b6f286ee4f..a488029573 100644
--- a/graphics/asymptote/base/three_margins.asy
+++ b/graphics/asymptote/base/three_margins.asy
@@ -27,7 +27,7 @@ margin3 operator +(margin3 ma, margin3 mb)
}
margin3 NoMargin3()
-{
+{
return new marginT3(path3 g, pen) {
marginT3 margin;
margin.begin=margin.end=0;
@@ -35,9 +35,9 @@ margin3 NoMargin3()
return margin;
};
}
-
+
margin3 Margin3(real begin, real end)
-{
+{
return new marginT3(path3 g, pen p) {
marginT3 margin;
real factor=labelmargin(p);
@@ -48,9 +48,9 @@ margin3 Margin3(real begin, real end)
return margin;
};
}
-
+
margin3 PenMargin3(real begin, real end)
-{
+{
return new marginT3(path3 g, pen p) {
marginT3 margin;
real factor=linewidth(p);
@@ -60,9 +60,9 @@ margin3 PenMargin3(real begin, real end)
return margin;
};
}
-
+
margin3 DotMargin3(real begin, real end)
-{
+{
return new marginT3(path3 g, pen p) {
marginT3 margin;
real margindot(real x) {return x > 0 ? dotfactor*x : x;}
@@ -73,9 +73,9 @@ margin3 DotMargin3(real begin, real end)
return margin;
};
}
-
+
margin3 TrueMargin3(real begin, real end)
-{
+{
return new marginT3(path3 g, pen p) {
marginT3 margin;
margin.begin=begin;
@@ -84,7 +84,7 @@ margin3 TrueMargin3(real begin, real end)
return margin;
};
}
-
+
margin3 NoMargin3=NoMargin3(),
BeginMargin3=Margin3(1,0),
Margin3=Margin3(0,1),
diff --git a/graphics/asymptote/base/three_surface.asy b/graphics/asymptote/base/three_surface.asy
index 77bdc6a998..e993c8d713 100644
--- a/graphics/asymptote/base/three_surface.asy
+++ b/graphics/asymptote/base/three_surface.asy
@@ -34,7 +34,7 @@ struct patch {
}
path3 externaltriangular() {
- return
+ return
P[0][0]..controls P[1][0] and P[2][0]..
P[3][0]..controls P[3][1] and P[3][2]..
P[3][3]..controls P[2][2] and P[1][1]..cycle;
@@ -91,7 +91,7 @@ struct patch {
new triple[] {Bv(1,v),z1},new bool[] {straight,false},false);
}
- triple point(real u, real v) {
+ triple point(real u, real v) {
return bezier(Bu(0,u),Bu(1,u),Bu(2,u),Bu(3,u),v);
}
@@ -237,7 +237,7 @@ struct patch {
color(normal11(),nocolors ? m : colors[2],light),
color(normal01(),nocolors ? m : colors[3],light)};
}
-
+
pen[] colorstriangular(material m, light light=currentlight) {
bool nocolors=colors.length == 0;
if(planar) {
@@ -250,7 +250,7 @@ struct patch {
color(normal10(),nocolors ? m : colors[1],light),
color(normal01(),nocolors ? m : colors[2],light)};
}
-
+
triple min3,max3;
bool havemin3,havemax3;
@@ -332,7 +332,7 @@ struct patch {
void operator init(patch s) {
operator init(s.P,s.colors,s.straight,s.planar,s.triangular);
}
-
+
// A constructor for a cyclic path3 of length 3 with a specified
// internal point, corner normals, and pens (rendered as a Bezier triangle).
void operator init(path3 external, triple internal, pen[] colors=new pen[],
@@ -406,51 +406,65 @@ struct patch {
};
}
- // A constructor for a convex quadrilateral.
+ // A constructor for a triangle or convex quadrilateral.
void operator init(triple[] external, triple[] internal=new triple[],
pen[] colors=new pen[], bool3 planar=default) {
init();
- if(internal.length == 0 && planar == default)
- this.planar=normal(external) != O;
- else this.planar=planar;
+ straight=true;
if(colors.length != 0)
this.colors=copy(colors);
- if(internal.length == 0) {
- internal=new triple[4];
+ if(external.length == 3) {
+ P=new triple[][] {
+ {external[0]},
+ {interp(external[0],external[1],1/3),
+ interp(external[2],external[0],2/3)},
+ {interp(external[0],external[1],2/3),sum(external)/3,
+ interp(external[2],external[0],1/3)},
+ {external[1],interp(external[1],external[2],1/3),
+ interp(external[1],external[2],2/3),external[2]}
+ };
+ planar=true;
+ triangular=true;
+ } else {
+ if(internal.length == 0 && planar == default)
+ this.planar=normal(external) != O;
+ else this.planar=planar;
+
+ if(internal.length == 0) {
+ internal=new triple[4];
+ for(int j=0; j < 4; ++j)
+ internal[j]=nineth*(4*external[j]+2*external[(j+1)%4]+
+ external[(j+2)%4]+2*external[(j+3)%4]);
+ }
+
+ triple delta[]=new triple[4];
for(int j=0; j < 4; ++j)
- internal[j]=nineth*(4*external[j]+2*external[(j+1)%4]+
- external[(j+2)%4]+2*external[(j+3)%4]);
+ delta[j]=(external[(j+1)% 4]-external[j])/3;
+
+ P=new triple[][] {
+ {external[0],external[0]-delta[3],external[3]+delta[3],external[3]},
+ {external[0]+delta[0],internal[0],internal[3],external[3]-delta[2]},
+ {external[1]-delta[0],internal[1],internal[2],external[2]+delta[2]},
+ {external[1],external[1]+delta[1],external[2]-delta[1],external[2]}
+ };
}
-
- straight=true;
-
- triple delta[]=new triple[4];
- for(int j=0; j < 4; ++j)
- delta[j]=(external[(j+1)% 4]-external[j])/3;
-
- P=new triple[][] {
- {external[0],external[0]-delta[3],external[3]+delta[3],external[3]},
- {external[0]+delta[0],internal[0],internal[3],external[3]-delta[2]},
- {external[1]-delta[0],internal[1],internal[2],external[2]+delta[2]},
- {external[1],external[1]+delta[1],external[2]-delta[1],external[2]}
- };
}
}
patch operator * (transform3 t, patch s)
-{
+{
patch S;
S.P=new triple[s.P.length][];
- for(int i=0; i < s.P.length; ++i) {
+ for(int i=0; i < s.P.length; ++i) {
triple[] si=s.P[i];
triple[] Si=S.P[i];
for(int j=0; j < si.length; ++j)
- Si[j]=t*si[j];
+ Si[j]=t*si[j];
}
-
+
S.colors=copy(s.colors);
S.planar=s.planar;
S.straight=s.straight;
@@ -458,8 +472,8 @@ patch operator * (transform3 t, patch s)
S.init();
return S;
}
-
-patch reverse(patch s)
+
+patch reverse(patch s)
{
assert(!s.triangular);
patch S;
@@ -505,7 +519,7 @@ pair[][] coons(path p)
p=p--cycle--cycle;
else if(L == 3)
p=p--cycle;
-
+
pair[] internal=new pair[4];
for(int j=0; j < 4; ++j) {
internal[j]=nineth*(-4*point(p,j)
@@ -533,12 +547,12 @@ path[] regularize(path p, bool checkboundary=true)
s.append(regularize(g,checkboundary));
return s;
}
-
+
bool straight=piecewisestraight(p);
if(L <= 3 && straight) {
return new path[] {p};
}
-
+
// Split p along the angle bisector at t.
bool split(path p, real t) {
pair dir=dir(p,t);
@@ -574,7 +588,7 @@ path[] regularize(path p, bool checkboundary=true)
if(straight)
return new path[] {p};
-
+
pair[][] P=coons(p);
// Check for degeneracy.
@@ -585,12 +599,12 @@ path[] regularize(path p, bool checkboundary=true)
for(int j=0; j < 4; ++j)
U[i][j]=P[i+1][j]-P[i][j];
}
-
+
for(int i=0; i < 4; ++i) {
for(int j=0; j < 3; ++j)
V[i][j]=P[i][j+1]-P[i][j];
}
-
+
int[] choose2={1,2,1};
int[] choose3={1,3,3,1};
@@ -670,7 +684,7 @@ path[] regularize(path p, bool checkboundary=true)
c[3] += w*(conj(P[0][j]-P[1][j])*P[0][i]).y; // u=0
}
}
-
+
pair BuP(int j, real u) {
return bezierP(P[0][j],P[1][j],P[2][j],P[3][j],u);
}
@@ -709,7 +723,7 @@ path[] regularize(path p, bool checkboundary=true)
// Split at the worst boundary degeneracy.
if(M < 0 && split(p,cut)) return s;
}
-
+
// Split arbitrarily to resolve any remaining (internal) degeneracy.
checkboundary=false;
for(int i=0; i < L; ++i)
@@ -730,7 +744,7 @@ struct surface {
int index[][];// Position of patch corresponding to major U,V parameter in s.
bool vcyclic;
transform3 T=identity4;
-
+
drawfcn draw;
bool PRCprimitive=true; // True unless no PRC primitive is available.
@@ -790,7 +804,7 @@ struct surface {
int V=floor(v);
int index=index.length == 0 ? U+V : index[U][V];
return s[index].point(u-U,v-V);
- }
+ }
triple normal(real u, real v) {
int U=floor(u);
@@ -798,25 +812,25 @@ struct surface {
int index=index.length == 0 ? U+V : index[U][V];
return s[index].normal(u-U,v-V);
}
-
- void ucyclic(bool f)
+
+ void ucyclic(bool f)
{
index.cyclic=f;
}
-
- void vcyclic(bool f)
+
+ void vcyclic(bool f)
{
for(int[] i : index)
i.cyclic=f;
vcyclic=f;
}
-
- bool ucyclic()
+
+ bool ucyclic()
{
return index.cyclic;
}
-
- bool vcyclic()
+
+ bool vcyclic()
{
return vcyclic;
}
@@ -830,7 +844,7 @@ struct surface {
g=g&s[i].uequals(u-U);
return vcyclic() ? g&cycle : g;
}
-
+
path3 vequals(real v) {
if(index.length == 0) return nullpath3;
int V=floor(v);
@@ -839,7 +853,7 @@ struct surface {
g=g&s[i[V]].vequals(v-V);
return ucyclic() ? g&cycle : g;
}
-
+
// A constructor for a possibly nonconvex simple cyclic path in a given
// plane.
void operator init(path p, triple plane(pair)=XYplane) {
@@ -880,12 +894,12 @@ struct surface {
return;
}
}
-
+
if(L <= 4 || internal.length > 0) {
s.push(patch(external,internal,colors,planar));
return;
}
-
+
// Path is not planar; split into patches.
real factor=1/L;
pen[] p;
@@ -968,7 +982,7 @@ struct surface {
typedef pen colorfcn(int i, real j);
bool defaultcolors=(colorfcn) color == null;
-
+
for(int i=0; i < L; ++i) {
path3 h=subpath(g,i,i+1);
path3 r=reverse(h);
@@ -985,7 +999,7 @@ struct surface {
}
test(maxtimes(H));
test(mintimes(H));
-
+
perp=unit(perp);
triple normal=unit(cross(axis,perp));
triple dir(real j) {return Cos(j)*normal-Sin(j)*perp;}
@@ -1023,7 +1037,7 @@ struct surface {
}
surface operator * (transform3 t, surface s)
-{
+{
surface S;
S.s=new patch[s.s.length];
for(int i=0; i < s.s.length; ++i)
@@ -1033,7 +1047,7 @@ surface operator * (transform3 t, surface s)
S.T=t*s.T;
S.draw=s.draw;
S.PRCprimitive=s.PRCprimitive;
-
+
return S;
}
@@ -1048,7 +1062,7 @@ triple min(surface s)
bound=s.s[i].min(bound);
return bound;
}
-
+
triple max(surface s)
{
if(s.s.length == 0)
@@ -1068,7 +1082,7 @@ pair min(surface s, projection P)
bound=s.s[i].min(P,bound);
return bound;
}
-
+
pair max(surface s, projection P)
{
if(s.s.length == 0)
@@ -1153,13 +1167,13 @@ triple[][][][] split(triple[][] P, real u=0.5, real v=0.5)
triple[] P1=P[1];
triple[] P2=P[2];
triple[] P3=P[3];
-
+
// slice horizontally
triple[] c0=split(P0[0],P0[1],P0[2],P0[3],v);
triple[] c1=split(P1[0],P1[1],P1[2],P1[3],v);
triple[] c2=split(P2[0],P2[1],P2[2],P2[3],v);
triple[] c3=split(P3[0],P3[1],P3[2],P3[3],v);
-
+
// bottom patch
triple[] c4=split(P0[0],P1[0],P2[0],P3[0],u);
triple[] c5=split(c0[0],c1[0],c2[0],c3[0],u);
@@ -1242,7 +1256,7 @@ triple[][] subpatchbegin(triple[][] P, real u, real v)
{c4[2],c5[2],c6[2],c7[2]}};
}
-triple[][] subpatch(triple[][] P, pair a, pair b)
+triple[][] subpatch(triple[][] P, pair a, pair b)
{
return subpatchend(subpatchbegin(P,b.x,b.y),a.x/b.x,a.y/b.y);
}
@@ -1294,7 +1308,7 @@ real[][] intersections(path3 p, surface s, real fuzz=-1)
static real Fuzz=1000*realEpsilon;
real fuzz=max(10*fuzz,Fuzz*max(abs(min(s)),abs(max(s))));
-
+
// Remove intrapatch duplicate points.
for(int i=0; i < T.length; ++i) {
triple v=point(p,T[i][0]);
@@ -1331,7 +1345,7 @@ bool overlap(triple[][] p, triple[][] q, real fuzz=-1)
if(fuzz == -1)
fuzz=1000*realEpsilon*max(abs(pmin),abs(pmax),abs(qmin),abs(qmax));
-
+
return
pmax.x+fuzz >= qmin.x &&
pmax.y+fuzz >= qmin.y &&
@@ -1346,19 +1360,6 @@ triple point(patch s, real u, real v)
return s.point(u,v);
}
-struct interaction
-{
- int type;
- bool targetsize;
- void operator init(int type, bool targetsize=false) {
- this.type=type;
- this.targetsize=targetsize;
- }
-}
-
-restricted interaction Embedded=interaction(0);
-restricted interaction Billboard=interaction(1);
-
interaction LabelInteraction()
{
return settings.autobillboard ? Billboard : Embedded;
@@ -1369,8 +1370,8 @@ material material(material m, light light, bool colors=false)
return light.on() || invisible((pen) m) ? m : emissive(m,colors);
}
-void draw3D(frame f, patch s, triple center=O, material m,
- light light=currentlight, interaction interaction=Embedded,
+void draw3D(frame f, patch s, material m,
+ light light=currentlight, render render=defaultrender,
bool primitive=false)
{
bool straight=s.straight && s.planar;
@@ -1381,13 +1382,15 @@ void draw3D(frame f, patch s, triple center=O, material m,
if(s.colors.length > 0) {
if(prc() && light.on())
straight=false; // PRC vertex colors (for quads only) ignore lighting
+ m=material(m);
m.diffuse(mean(s.colors));
}
m=material(m,light,s.colors.length > 0);
-
- (s.triangular ? drawbeziertriangle : draw)
- (f,s.P,center,straight,m.p,m.opacity,m.shininess,
- m.metallic,m.fresnel0,s.colors,interaction.type,digits,primitive);
+
+ (s.triangular ? drawbeziertriangle : draw)
+ (f,s.P,render.interaction.center,straight,m.p,m.opacity,m.shininess,
+ m.metallic,m.fresnel0,s.colors,render.interaction.type,digits,
+ primitive);
}
void _draw(frame f, path3 g, triple center=O, material m,
@@ -1417,7 +1420,7 @@ int computeNormals(triple[] v, int[][] vi, triple[] n, int[][] ni)
// Draw triangles on a frame.
void draw(frame f, triple[] v, int[][] vi,
triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={},
- int[][] pi={}, light light=currentlight)
+ int[][] pi={}, light light=currentlight, render render=defaultrender)
{
bool normals=n.length > 0;
if(!normals) {
@@ -1427,13 +1430,15 @@ void draw(frame f, triple[] v, int[][] vi,
if(p.length > 0)
m=mean(p);
m=material(m,light);
- draw(f,v,vi,n,ni,m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,p,pi);
+ draw(f,v,vi,render.interaction.center,n,ni,
+ m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,p,pi,
+ render.interaction.type);
}
-
+
// Draw triangles on a picture.
void draw(picture pic=currentpicture, triple[] v, int[][] vi,
triple[] n={}, int[][] ni={}, material m=currentpen, pen[] p={},
- int[][] pi={}, light light=currentlight)
+ int[][] pi={}, light light=currentlight, render render=defaultrender)
{
bool prc=prc();
bool normals=n.length > 0;
@@ -1448,7 +1453,9 @@ void draw(picture pic=currentpicture, triple[] v, int[][] vi,
triple[] n=t*n;
if(is3D()) {
- draw(f,v,vi,n,ni,m,p,pi,light);
+ render Render=render(render,interaction(render.interaction,
+ t*render.interaction.center));
+ draw(f,v,vi,n,ni,m,p,pi,light,Render);
if(pic != null) {
for(int[] vii : vi)
for(int viij : vii)
@@ -1487,7 +1494,7 @@ void draw(picture pic=currentpicture, triple[] v, int[][] vi,
}
}
}
- }
+ }
},true);
for(int[] vii : vi)
@@ -1502,7 +1509,7 @@ void tensorshade(transform t=identity(), frame f, patch s,
if(s.triangular) {
p=s.colorstriangular(m,light);
p.push(p[0]);
- s=tensor(s);
+ s=tensor(s);
} else p=s.colors(m,light);
path g=t*project(s.external(),P,1);
pair[] internal=t*project(s.internal(),P);
@@ -1529,11 +1536,12 @@ void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1,
bool is3D=is3D();
if(is3D) {
bool prc=prc();
- if(s.draw != null && (settings.outformat == "html" ||
- (prc && s.PRCprimitive))) {
+ if(s.draw != null && (primitive() || (prc && s.PRCprimitive))) {
+ bool noprerender=settings.prerender == 0;
for(int k=0; k < s.s.length; ++k)
- draw3D(f,s.s[k],surfacepen[k],light,primitive=true);
- s.draw(f,s.T,surfacepen,light,render);
+ draw3D(f,s.s[k],surfacepen[k],light,render,primitive=noprerender);
+ if(noprerender)
+ s.draw(f,s.T,surfacepen,light,render);
} else {
bool group=name != "" || render.defaultnames;
if(group)
@@ -1557,7 +1565,7 @@ void draw(transform t=identity(), frame f, surface s, int nu=1, int nv=1,
for(int p=depth.length-1; p >= 0; --p) {
real[] a=depth[p];
int k=round(a[1]);
- draw3D(f,s.s[k],surfacepen[k],light);
+ draw3D(f,s.s[k],surfacepen[k],light,render);
}
if(group)
@@ -1646,8 +1654,11 @@ void draw(picture pic=currentpicture, surface s, int nu=1, int nv=1,
pic.add(new void(frame f, transform3 t, picture pic, projection P) {
surface S=t*s;
- if(is3D())
- draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name,render);
+ if(is3D()) {
+ render Render=render(render,interaction(render.interaction,
+ t*render.interaction.center));
+ draw(f,S,nu,nv,surfacepen,meshpen,light,meshlight,name,Render);
+ }
if(pic != null) {
pic.add(new void(frame f, transform T) {
draw(T,f,S,nu,nv,surfacepen,meshpen,light,meshlight,P);
@@ -1724,7 +1735,7 @@ surface extrude(explicit path[] p, triple axis=Z)
return s;
}
-triple rectify(triple dir)
+triple rectify(triple dir)
{
real scale=max(abs(dir.x),abs(dir.y),abs(dir.z));
if(scale != 0) dir *= 0.5/scale;
@@ -1832,16 +1843,17 @@ void label(frame f, Label L, triple position, align align=NoAlign,
transform3 positioning=
shift(L.align.is3D ? position+L.align.dir3*labelmargin(L.p) : position);
frame f1,f2,f3;
- begingroup3(f1,name,render);
- if(L.defaulttransform3)
- begingroup3(f3,render,position,interaction.type);
- else {
- begingroup3(f2,render,position,interaction.type);
- begingroup3(f3,render,position);
- }
+ render Render=render(render,interaction(interaction,position));
+ begingroup3(f1,name,render);
+ if(L.defaulttransform3)
+ begingroup3(f3,Render);
+ else {
+ begingroup3(f2,Render);
+ begingroup3(f3,Render);
+ }
for(patch S : s.s) {
S=centering*S;
- draw3D(f3,S,position,L.p,light,interaction);
+ draw3D(f3,S,L.p,light,Render);
// Fill subdivision cracks
if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
_draw(f3,S.external(),position,L.p,light,interaction);
@@ -1861,7 +1873,7 @@ void label(frame f, Label L, triple position, align align=NoAlign,
for(patch S : surface(L,position).s) {
triple V=L.align.is3D ? position+L.align.dir3*labelmargin(L.p) :
position;
- draw3D(f,S,V,L.p,light,interaction);
+ draw3D(f,S,L.p,light,render(interaction(interaction,center=V)));
// Fill subdivision cracks
if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
_draw(f,S.external(),V,L.p,light,interaction);
@@ -1894,7 +1906,7 @@ void label(picture pic=currentpicture, Label L, triple position,
L.align(align);
L.p(p);
L.position(0);
-
+
pic.add(new void(frame f, transform3 t, picture pic2, projection P) {
// Handle relative projected 3D alignments.
bool prc=prc();
@@ -1903,7 +1915,7 @@ void label(picture pic=currentpicture, Label L, triple position,
if(!align.is3D && L.align.relative && L.align.dir3 != O &&
determinant(P.t) != 0)
L.align(L.align.dir*unit(project(v+L.align.dir3,P.t)-project(v,P.t)));
-
+
if(interaction.targetsize && settings.render != 0)
L.T=L.T*scale(abs(P.camera-v)/abs(P.vector()));
transform3 T=transform3(P);
@@ -1922,15 +1934,16 @@ void label(picture pic=currentpicture, Label L, triple position,
shift(L.align.is3D ? v+L.align.dir3*labelmargin(L.p) : v);
frame f1,f2,f3;
begingroup3(f1,name,render);
+ render Render=render(render,interaction(interaction,v));
if(L.defaulttransform3)
- begingroup3(f3,render,v,interaction.type);
+ begingroup3(f3,Render);
else {
- begingroup3(f2,render,v,interaction.type);
- begingroup3(f3,render,v);
+ begingroup3(f2,Render);
+ begingroup3(f3,Render);
}
for(patch S : s.s) {
S=centering*S;
- draw3D(f3,S,v,L.p,light,interaction);
+ draw3D(f3,S,L.p,light,Render);
// Fill subdivision cracks
if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
_draw(f3,S.external(),v,L.p,light,interaction);
@@ -1950,7 +1963,8 @@ void label(picture pic=currentpicture, Label L, triple position,
begingroup3(f,name,render);
for(patch S : surface(L,v,bbox=P.bboxonly).s) {
triple V=L.align.is3D ? v+L.align.dir3*labelmargin(L.p) : v;
- draw3D(f,S,V,L.p,light,interaction);
+ render Render=render(render,interaction(interaction,V));
+ draw3D(f,S,L.p,light,Render);
// Fill subdivision cracks
if(prc && render.labelfill && opacity(L.p) == 1 && !lighton)
_draw(f,S.external(),V,L.p,light,interaction);
@@ -1958,7 +1972,7 @@ void label(picture pic=currentpicture, Label L, triple position,
endgroup3(f);
}
}
-
+
if(pic2 != null) {
pen p=color(L.T3*Z,L.p,light,shiftless(P.T.modelview));
if(L.defaulttransform3) {
@@ -1975,11 +1989,11 @@ void label(picture pic=currentpicture, Label L, triple position,
fill(f,T*project(S.external(),P,1),p);
});
}
-
+
},!L.defaulttransform3);
Label L=L.copy();
-
+
if(interaction.targetsize && settings.render != 0)
L.T=L.T*scale(abs(currentprojection.camera-position)/
abs(currentprojection.vector()));
@@ -2008,7 +2022,7 @@ void label(picture pic=currentpicture, Label L, path3 g, align align=NoAlign,
a.init(-I*(position <= sqrtEpsilon ? S :
position >= length(g)-sqrtEpsilon ? N : E),relative=true);
a.dir3=dir(g,position); // Pass 3D direction via unused field.
- L.align(a);
+ L.align(a);
}
label(pic,L,point(g,position),light,name,interaction);
}
@@ -2063,7 +2077,7 @@ surface surface(Label L, surface s, real uoffset, real voffset,
for(path g : regularize(p)) {
path3 b;
bool extrude=height > 0;
- if(bottom || extrude)
+ if(bottom || extrude)
b=transpath(g,0);
if(bottom) s.s.push(patch(b));
if(top || extrude) {
@@ -2390,7 +2404,7 @@ pair maxbound(triple[][] A, projection P)
return b;
}
-triple[][] operator / (triple[][] a, real[][] b)
+triple[][] operator / (triple[][] a, real[][] b)
{
triple[][] A=new triple[a.length][];
for(int i=0; i < a.length; ++i) {
diff --git a/graphics/asymptote/base/three_tube.asy b/graphics/asymptote/base/three_tube.asy
index 60085a7d51..5c22f4d29b 100644
--- a/graphics/asymptote/base/three_tube.asy
+++ b/graphics/asymptote/base/three_tube.asy
@@ -100,6 +100,17 @@ rmf[] rmf(triple z0, triple c0, triple c1, triple z1, real[] t, triple perp=O)
return R;
}
+
+drawfcn drawTube(triple[] g, real w, triple min, triple max) {
+ return new void(frame f, transform3 t=identity4, material[] m,
+ light light=currentlight, render render=defaultrender)
+ {
+ material m=material(m[0],light);
+ drawTube(f,t*g,w,m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,
+ t*min,t*max,m.opacity == 1);
+ };
+}
+
surface tube(triple z0, triple c0, triple c1, triple z1, real w)
{
surface s;
@@ -125,13 +136,7 @@ surface tube(triple z0, triple c0, triple c1, triple z1, real w)
f(t3);
s.PRCprimitive=false;
- s.draw=new void(frame f, transform3 t=identity4, material[] m,
- light light=currentlight, render render=defaultrender)
- {
- material m=material(m[0],light);
- drawTube(f,t*g,w,m.p,m.opacity,m.shininess,m.metallic,m.fresnel0,
- t*min(s),t*max(s),m.opacity == 1);
- };
+ s.draw=drawTube(g,w,min(s),max(s));
return s;
}
@@ -153,7 +158,7 @@ struct tube
void Null(transform3) {}
void Null(transform3, bool) {}
-
+
surface[] render(path3 g, real r) {
triple z0=point(g,0);
triple c0=postcontrol(g,0);
@@ -174,7 +179,7 @@ struct tube
pair a0=threshold(z0,c0,c1);
pair a1=threshold(z1,c1,c0);
real rL=r*arclength(z0,c0,c1,z1)*tubethreshold;
- if((a0.x >= norm && rL*a0.y^2 > a0.x^8) ||
+ if((a0.x >= norm && rL*a0.y^2 > a0.x^8) ||
(a1.x >= norm && rL*a1.y^2 > a1.x^8)) {
triple m0=0.5*(z0+c0);
triple m1=0.5*(c0+c1);
@@ -214,7 +219,7 @@ struct tube
s.append(render(subpath(p,i,i+1),r));
}
}
-
+
transform3 t=scale3(r);
bool cyclic=cyclic(p);
int begin=0;
diff --git a/graphics/asymptote/base/trembling.asy b/graphics/asymptote/base/trembling.asy
index f9f0d6a747..6f696945af 100644
--- a/graphics/asymptote/base/trembling.asy
+++ b/graphics/asymptote/base/trembling.asy
@@ -17,14 +17,14 @@
// 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:
real magneticRadius=1; // unit is bp in postscript coordinates.
real trembleFuzz(){return min(1e-3,magneticRadius/10);}
@@ -34,7 +34,7 @@ real trembleAngle=4, trembleFrequency=0.5, trembleRandom=2;
struct tremble
{
static real test=5;
-
+
real angle,frequency,random,fuzz;
pair[] single(pair[] P)
@@ -141,7 +141,7 @@ struct tremble
this.random=random;
this.fuzz=fuzz;
}
-
+
path deform(path g...pair[] magneticPoints) {
/* Return g as it was handwriting.
The postcontrols and precontrols of the nodes of g will be rotated
diff --git a/graphics/asymptote/base/v3d.asy b/graphics/asymptote/base/v3d.asy
new file mode 100644
index 0000000000..0405a5d5bc
--- /dev/null
+++ b/graphics/asymptote/base/v3d.asy
@@ -0,0 +1,643 @@
+// Supakorn "Jamie" Rassameemasuang <jamievlin@outlook.com> and
+// John C. Bowman
+
+import three;
+import v3dtypes;
+import v3dheadertypes;
+
+struct triangleGroup
+{
+ triple[] positions;
+ triple[] normals;
+ pen[] colors;
+
+ int[][] positionIndices;
+ int[][] normalIndices;
+ int[][] colorIndices;
+}
+
+struct pixel
+{
+ triple point;
+ real width;
+}
+
+struct CameraInformation
+{
+ int canvasWidth;
+ int canvasHeight;
+ bool absolute;
+
+ triple b;
+ triple B;
+ bool orthographic;
+ real angle;
+ real Zoom0;
+ pair viewportMargin;
+
+ light light;
+
+ void setCameraInfo()
+ {
+ size(canvasWidth,canvasHeight);
+ triple center=0.5*(b.z+B.z)*Z;
+
+ if(orthographic)
+ currentprojection=orthographic(Z,target=center);
+ else
+ currentprojection=perspective(Z,Y,target=center,Zoom0,degrees(angle),autoadjust=false);
+ light.specular=light.diffuse;
+ currentlight=light;
+ }
+}
+
+transform3 Align(real polar, real azimuth)
+{
+ return align(dir(degrees(polar),degrees(azimuth)));
+}
+
+struct v3dfile
+{
+ file xdrfile;
+ int version;
+ bool hasCameraInfo=false;
+ CameraInformation info;
+ bool singleprecision=false;
+
+ triple[] centers;
+ material[] materials;
+
+ surface[][][] surfaces;
+ path3[][][] paths3;
+ triangleGroup[][][] triangles;
+ pixel[][] pixels;
+
+ void initSurface(int center, int material) {
+ if(!surfaces.initialized(center))
+ surfaces[center]=new surface[][];
+ if(!surfaces[center].initialized(material))
+ surfaces[center][material]=new surface[] {new surface};
+ }
+
+ void initPath3(int center, int material) {
+ if(!paths3.initialized(center))
+ paths3[center]=new path3[][];
+ if(!paths3[center].initialized(material))
+ paths3[center][material]=new path3[];
+ }
+
+ void initTriangleGroup(int center, int material) {
+ if (!triangles.initialized(center))
+ triangles[center]=new triangleGroup[][];
+ if(!triangles[center].initialized(material))
+ triangles[center][material]=new triangleGroup[];
+ }
+
+ void initPixel(int material) {
+ if(!pixels.initialized(material))
+ pixels[material]=new pixel[];
+ }
+
+ void surface(int center, int material, patch p) {
+ initSurface(center,material);
+ surfaces[center][material][0].s.push(p);
+ }
+
+ void primitive(int center, int material, surface s) {
+ initSurface(center,material);
+ surfaces[center][material].push(s);
+ }
+
+ void path3(int center, int material, path3 p) {
+ initPath3(center,material);
+ paths3[center][material].push(p);
+ }
+
+ void triangleGroup(int center, int material, triangleGroup g) {
+ initTriangleGroup(center,material);
+ triangles[center][material].push(g);
+ }
+
+ void pixel(int material, pixel P) {
+ initPixel(material);
+ pixels[material].push(P);
+ }
+
+ void operator init(string name)
+ {
+ xdrfile=input(name, mode="xdrgz");
+ version=xdrfile;
+
+ int doubleprecision=xdrfile;
+ singleprecision=doubleprecision == 0;
+ xdrfile.singlereal(singleprecision);
+ }
+
+ int getType()
+ {
+ return xdrfile;
+ }
+
+ void setCameraInfo()
+ {
+ if(hasCameraInfo)
+ info.setCameraInfo();
+ }
+
+ pen[] readColorData(int size=4, bool alpha=true)
+ {
+ xdrfile.singlereal(true);
+
+ xdrfile.dimension(alpha ? 4 : 3);
+ pen[] newPen=new pen[size];
+ for (int i=0; i < size; ++i)
+ {
+ newPen[i]=alpha ? rgba(xdrfile) : rgb((real[]) xdrfile);
+ }
+
+ xdrfile.singlereal(singleprecision);
+
+ return newPen;
+ }
+
+ CameraInformation processHeader()
+ {
+ CameraInformation ci;
+
+ int entryCount=xdrfile;
+ for (int i=0;i<entryCount;++i)
+ {
+ int headerKey=xdrfile;
+ int headerSz=xdrfile;
+
+ if (headerKey == v3dheadertypes.canvasWidth)
+ {
+ ci.canvasWidth=xdrfile;
+ }
+ else if (headerKey == v3dheadertypes.canvasHeight)
+ {
+ ci.canvasHeight=xdrfile;
+ }
+ else if (headerKey == v3dheadertypes.absolute)
+ {
+ int val=xdrfile;
+ ci.absolute=(val != 0);
+ }
+ else if (headerKey == v3dheadertypes.minBound)
+ {
+ ci.b=xdrfile;
+ }
+ else if (headerKey == v3dheadertypes.maxBound)
+ {
+ ci.B=xdrfile;
+ }
+ else if (headerKey == v3dheadertypes.orthographic)
+ {
+ int val=xdrfile;
+ ci.orthographic=(val != 0);
+ }
+ else if (headerKey == v3dheadertypes.angleOfView)
+ {
+ ci.angle=xdrfile;
+ }
+ else if (headerKey == v3dheadertypes.initialZoom)
+ {
+ ci.Zoom0=xdrfile;
+ }
+ else if (headerKey==v3dheadertypes.viewportMargin)
+ {
+ ci.viewportMargin=xdrfile;
+ }
+ else if (headerKey==v3dheadertypes.background)
+ {
+ ci.light.background=readColorData(1)[0];
+ }
+ else if (headerKey==v3dheadertypes.light)
+ {
+ triple position=xdrfile;
+ ci.light.position.push(position);
+ ci.light.diffuse.push(rgba(readColorData(1,false)[0]));
+ }
+ else
+ {
+ xdrfile.dimension(headerSz);
+ int[] _dmp=xdrfile;
+ }
+ }
+ return ci;
+ }
+
+ material readMaterial() {
+ xdrfile.dimension(4);
+ xdrfile.singlereal(true);
+
+ pen diffusePen=rgba(xdrfile);
+ pen emissivePen=rgba(xdrfile);
+ pen specularPen=rgba(xdrfile);
+
+ xdrfile.dimension(3);
+ real[] params=xdrfile;
+ real shininess=params[0];
+ real metallic=params[1];
+ real F0=params[2];
+
+ xdrfile.singlereal(singleprecision);
+
+ return material(diffusePen,emissivePen,specularPen,1,shininess,
+ metallic,F0);
+ }
+
+ triple[][] readRawPatchData() {
+ triple[][] val;
+ xdrfile.dimension(4,4);
+ val=xdrfile;
+ return val;
+ }
+
+ triple[][] readRawTriangleData() {
+ triple[][] val;
+
+ for(int i=0; i < 4; ++i) {
+ xdrfile.dimension(i+1);
+ triple[] v=xdrfile;
+ val.push(v);
+ }
+ return val;
+ }
+
+ void readBezierPatch() {
+ triple[][] val=readRawPatchData();
+ int center=xdrfile;
+ int material=xdrfile;
+ surface(center,material,patch(val));
+ }
+
+ void readBezierTriangle() {
+ triple[][] val=readRawTriangleData();
+ int center=xdrfile;
+ int material=xdrfile;
+ surface(center,material,patch(val,triangular=true));
+ }
+
+ triple[] readCenters() {
+ int centerCount=xdrfile;
+ xdrfile.dimension(centerCount);
+ triple[] centersFetched;
+ if (centerCount>0)
+ centersFetched=xdrfile;
+ return centersFetched;
+ }
+
+ void readBezierPatchColor() {
+ triple[][] val=readRawPatchData();
+ int center=xdrfile;
+ int material=xdrfile;
+ pen[] colors=readColorData(4);
+ surface(center,material,patch(val,colors=colors));
+ }
+
+ void readBezierTriangleColor() {
+ triple[][] val=readRawTriangleData();
+ int center=xdrfile;
+ int material=xdrfile;
+ pen[] colors=readColorData(3);
+ surface(center,material,patch(val,triangular=true,colors=colors));
+ }
+
+ void readSphere() {
+ triple origin=xdrfile;
+ real radius=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ surface s=shift(origin)*scale3(radius)*unitsphere;
+ s.draw=unitsphere.draw;
+ primitive(center,material,s);
+ }
+
+ void readHemisphere() {
+ triple origin=xdrfile;
+ real radius=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ real polar=xdrfile;
+ real azimuth=xdrfile;
+
+ surface s=shift(origin)*Align(polar,azimuth)*scale3(radius)*unithemisphere;
+ s.draw=unithemisphere.draw;
+ primitive(center,material,s);
+ }
+
+ void readDisk() {
+ triple origin=xdrfile;
+ real radius=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ real polar=xdrfile;
+ real azimuth=xdrfile;
+
+ surface s=shift(origin)*Align(polar,azimuth)*scale3(radius)*unitdisk;
+ s.draw=unitdisk.draw;
+ primitive(center,material,s);
+ }
+
+ void readPolygon(int n)
+ {
+ xdrfile.dimension(n);
+ triple[] val=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+ surface(center,material,patch(val));
+ }
+
+ void readPolygonColor(int n)
+ {
+ xdrfile.dimension(n);
+ triple[] val=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ pen[] colors=readColorData(n);
+ surface(center,material,patch(val,colors=colors));
+ }
+
+ void readCylinder() {
+ triple origin=xdrfile;
+ real radius=xdrfile;
+ real height=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ real polar=xdrfile;
+ real azimuth=xdrfile;
+
+ int core=xdrfile;
+
+ transform3 T=shift(origin)*Align(polar,azimuth)*
+ scale(radius,radius,height);
+ if(core != 0)
+ path3(center,material,T*(O--Z));
+
+ surface s=T*unitcylinder;
+ s.draw=unitcylinder.draw;
+ primitive(center,material,s);
+ }
+
+ void readTube() {
+ xdrfile.dimension(4);
+ triple[] g=xdrfile;
+
+ real width=xdrfile;
+ int center=xdrfile;
+ int material=xdrfile;
+
+ int core=xdrfile;
+
+ if(core != 0)
+ path3(center,material,g[0]..controls g[1] and g[2]..g[3]);
+
+ surface s=tube(g[0],g[1],g[2],g[3],width);
+ s.draw=drawTube(g,width,info.b,info.B);
+ primitive(center,material,s);
+ }
+
+ void readCurve() {
+ xdrfile.dimension(4);
+ triple[] points=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ path3(center,material,
+ points[0]..controls points[1] and points[2]..points[3]);
+ }
+
+ void readLine() {
+ xdrfile.dimension(2);
+ triple[] points=xdrfile;
+
+ int center=xdrfile;
+ int material=xdrfile;
+
+ path3(center,material,points[0]--points[1]);
+ }
+
+ void readTriangles() {
+ triangleGroup g;
+
+ int nI=xdrfile;
+
+ int nP=xdrfile;
+ xdrfile.dimension(nP);
+ g.positions=xdrfile;
+
+ int nN=xdrfile;
+ xdrfile.dimension(nN);
+ g.normals=xdrfile;
+
+ int explicitNI=xdrfile;
+
+ int nC=xdrfile;
+ int explicitCI;
+ if (nC > 0) {
+ g.colors=readColorData(nC);
+ explicitCI=xdrfile;
+ }
+
+ g.positionIndices=new int[nI][3];
+ g.normalIndices=new int[nI][3];
+ int[][] colorIndices;
+ if (nC > 0)
+ g.colorIndices=new int[nI][3];
+
+ for (int i=0; i < nI; ++i) {
+ xdrfile.dimension(3);
+ g.positionIndices[i]=xdrfile;
+ if(explicitNI != 0)
+ g.normalIndices[i]=xdrfile;
+ else
+ g.normalIndices[i]=g.positionIndices[i];
+ if(nC > 0) {
+ if(explicitCI != 0)
+ g.colorIndices[i]=xdrfile;
+ else
+ g.colorIndices[i]=g.positionIndices[i];
+ } else
+ g.colorIndices[i]=g.positionIndices[i];
+ }
+ int center=xdrfile;
+ int material=xdrfile;
+ triangleGroup(center,material,g);
+ }
+
+ void readPixel() {
+ pixel P;
+ P.point=xdrfile;
+ P.width=xdrfile;
+ int material=xdrfile;
+ pixel(material,P);
+ }
+
+ void process()
+ {
+ static bool processed;
+ if(processed) return;
+
+ while (!eof(xdrfile))
+ {
+ int ty=getType();
+ if(ty == v3dtypes.header)
+ {
+ hasCameraInfo=true;
+ info=processHeader();
+ }
+ else if(ty == v3dtypes.material)
+ {
+ materials.push(readMaterial());
+ }
+ else if(ty == v3dtypes.bezierPatch)
+ {
+ readBezierPatch();
+ }
+ else if(ty == v3dtypes.bezierTriangle)
+ {
+ readBezierTriangle();
+ }
+ else if(ty == v3dtypes.bezierPatchColor)
+ {
+ readBezierPatchColor();
+ }
+ else if(ty == v3dtypes.bezierTriangleColor)
+ {
+ readBezierTriangleColor();
+ }
+ else if(ty == v3dtypes.quad)
+ {
+ readPolygon(4);
+ }
+ else if(ty == v3dtypes.quadColor)
+ {
+ readPolygonColor(4);
+ }
+ else if(ty == v3dtypes.triangle)
+ {
+ readPolygon(3);
+ }
+ else if(ty == v3dtypes.triangleColor)
+ {
+ readPolygonColor(3);
+ }
+ else if(ty == v3dtypes.sphere)
+ {
+ readSphere();
+ }
+ else if(ty == v3dtypes.halfSphere)
+ {
+ readHemisphere();
+ }
+ else if(ty == v3dtypes.cylinder)
+ {
+ readCylinder();
+ }
+ else if(ty == v3dtypes.tube)
+ {
+ readTube();
+ }
+ else if(ty == v3dtypes.disk)
+ {
+ readDisk();
+ }
+ else if(ty == v3dtypes.curve)
+ {
+ readCurve();
+ }
+ else if(ty == v3dtypes.line)
+ {
+ readLine();
+ }
+ else if(ty == v3dtypes.triangles)
+ {
+ readTriangles();
+ }
+ else if(ty == v3dtypes.centers)
+ {
+ centers=readCenters();
+ }
+ else if(ty == v3dtypes.pixel)
+ {
+ readPixel();
+ }
+ else
+ {
+ // abort("Unknown type:"+string(ty));
+ }
+ }
+ processed=true;
+ }
+}
+
+void importv3d(string name)
+{
+ if(name == stripextension(name)) name += ".v3d";
+ v3dfile xf=v3dfile(name);
+ xf.process();
+ xf.setCameraInfo();
+
+ for(int c=0; c < xf.surfaces.length; ++c) {
+ triple center=c > 0 ? xf.centers[c-1] : O;
+ render r=render(interaction(c == 0 ? Embedded : Billboard,center=center));
+ surface[][] S=xf.surfaces[c];
+ for(int m=0; m < S.length; ++m)
+ if(S.initialized(m))
+ draw(S[m],xf.materials[m],r);
+ }
+
+ for(int c=0; c < xf.paths3.length; ++c) {
+ triple center=c > 0 ? xf.centers[c-1] : O;
+ render r=render(interaction(c == 0 ? Embedded : Billboard,center=center));
+ path3[][] G=xf.paths3[c];
+ for(int m=0; m < G.length; ++m)
+ if(G.initialized(m)) {
+ material material=xf.materials[m];
+ material.p[0] += thin();
+ draw(G[m],material,r);
+ }
+ }
+
+ for(int c=0;c < xf.triangles.length; ++c) {
+ triple center=c > 0 ? xf.centers[c-1] : O;
+ render r=render(interaction(c == 0 ? Embedded : Billboard,center=center));
+ triangleGroup[][] groups=xf.triangles[c];
+ for(int m=0; m < groups.length; ++m) {
+ if(groups.initialized(m)) {
+ material material=xf.materials[m];
+ triangleGroup[] triangleGroups=groups[m];
+ for(triangleGroup g : triangleGroups) {
+ if(g.colors.length > 0)
+ draw(g.positions,g.positionIndices,g.normals,g.normalIndices,
+ g.colors,g.colorIndices,r);
+ else
+ draw(g.positions,g.positionIndices,g.normals,g.normalIndices,
+ material,r);
+ }
+ }
+ }
+ }
+
+ for(int m=0; m < xf.pixels.length; ++m) {
+ if(xf.pixels.initialized(m)) {
+ material material=xf.materials[m];
+ pixel[] pixels=xf.pixels[m];
+ for(pixel P : pixels)
+ pixel(P.point,material.p[0],P.width);
+ }
+ }
+}
diff --git a/graphics/asymptote/base/v3dheadertypes.asy b/graphics/asymptote/base/v3dheadertypes.asy
new file mode 100644
index 0000000000..765d678080
--- /dev/null
+++ b/graphics/asymptote/base/v3dheadertypes.asy
@@ -0,0 +1,66 @@
+// Enum class for v3dheadertypes
+// AUTO-GENERATED from v3dheadertypes.csv
+// Generated at 2021-12-27 12:46:04.747922
+
+struct v3dheadertypes
+{
+ int canvasWidth=1;
+// UINT Canvas width
+
+ int canvasHeight=2;
+// UINT Canvas height
+
+ int absolute=3;
+// BOOL true: absolute size; false: scale to canvas
+
+ int minBound=4;
+// TRIPLE Scene minimum bounding box corners
+
+ int maxBound=5;
+// TRIPLE Scene maximum bounding box corners
+
+ int orthographic=6;
+// BOOL true: orthographic; false: perspective
+
+ int angleOfView=7;
+// REAL Field of view angle
+
+ int initialZoom=8;
+// REAL Initial zoom
+
+ int viewportShift=9;
+// PAIR Viewport shift (for perspective projection)
+
+ int viewportMargin=10;
+// PAIR Margin around viewport
+
+ int light=11;
+// RGB Direction and color of each point light source
+
+ int background=12;
+// RGBA Background color
+
+ int zoomFactor=13;
+// REAL Zoom base factor
+
+ int zoomPinchFactor=14;
+// REAL Zoom pinch factor
+
+ int zoomPinchCap=15;
+// REAL Zoom pinch limit
+
+ int zoomStep=16;
+// REAL Zoom power step
+
+ int shiftHoldDistance=17;
+// REAL Shift-mode maximum hold distance (pixels)
+
+ int shiftWaitTime=18;
+// REAL Shift-mode hold time (milliseconds)
+
+ int vibrateTime=19;
+// REAL Shift-mode vibrate time (milliseconds)
+
+};
+
+v3dheadertypes v3dheadertypes;// End of File
diff --git a/graphics/asymptote/base/v3dtypes.asy b/graphics/asymptote/base/v3dtypes.asy
new file mode 100644
index 0000000000..b5f19cd5cd
--- /dev/null
+++ b/graphics/asymptote/base/v3dtypes.asy
@@ -0,0 +1,34 @@
+// Enum class for v3dtypes
+// AUTO-GENERATED from v3dtypes.csv
+// Generated at 2021-12-27 12:46:04.684643
+
+struct v3dtypes
+{
+ int material=1;
+ int transform=2;
+ int element=3;
+ int centers=4;
+ int header=5;
+ int line=64;
+ int triangle=65;
+ int quad=66;
+ int curve=128;
+ int bezierTriangle=129;
+ int bezierPatch=130;
+ int lineColor=192;
+ int triangleColor=193;
+ int quadColor=194;
+ int curveColor=256;
+ int bezierTriangleColor=257;
+ int bezierPatchColor=258;
+ int triangles=512;
+ int disk=1024;
+ int cylinder=1025;
+ int tube=1026;
+ int sphere=1027;
+ int halfSphere=1028;
+ int animation=2048;
+ int pixel=4096;
+};
+
+v3dtypes v3dtypes;// End of File
diff --git a/graphics/asymptote/base/webgl/asygl.js b/graphics/asymptote/base/webgl/asygl.js
index db8810f260..8e02dcfbda 100644
--- a/graphics/asymptote/base/webgl/asygl.js
+++ b/graphics/asymptote/base/webgl/asygl.js
@@ -1,6 +1,6 @@
/*@license
AsyGL: Render Bezier patches and triangles via subdivision with WebGL.
- Copyright 2019-2020: John C. Bowman and Supakorn "Jamie" Rassameemasmuang
+ Copyright 2019-2021: John C. Bowman and Supakorn "Jamie" Rassameemasmuang
University of Alberta
This program is free software; you can redistribute it and/or modify
@@ -36,4 +36,4 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.*/
-let vertex="\nattribute vec3 position;\n#ifdef WIDTH\nattribute float width;\n#endif\n#ifdef NORMAL\nattribute vec3 normal;\n#endif\nattribute float materialIndex;\n#ifdef COLOR\nattribute vec4 color;\n#endif\n\nuniform mat3 normMat;\nuniform mat4 viewMat;\nuniform mat4 projViewMat;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nvarying vec3 ViewPosition;\n#endif\nvarying vec3 Normal;\n#endif\nvarying vec4 diffuse;\nvarying vec3 specular;\nvarying float roughness,metallic,fresnel0;\nvarying vec4 emissive;\n\nstruct Material {\n vec4 diffuse,emissive,specular;\n vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n\nvoid main(void)\n{\n vec4 v=vec4(position,1.0);\n gl_Position=projViewMat*v;\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\n ViewPosition=(viewMat*v).xyz;\n#endif \n Normal=normalize(normal*normMat);\n \n Material m;\n#ifdef TRANSPARENT\n m=Materials[int(abs(materialIndex))-1];\n emissive=m.emissive;\n if(materialIndex >= 0.0) {\n diffuse=m.diffuse;\n } else {\n diffuse=color;\n#if nlights == 0\n emissive += color;\n#endif\n }\n#else\n m=Materials[int(materialIndex)];\n emissive=m.emissive;\n#ifdef COLOR\n diffuse=color;\n#if nlights == 0\n emissive += color;\n#endif\n#else\n diffuse=m.diffuse;\n#endif\n#endif\n specular=m.specular.rgb;\n vec4 parameters=m.parameters;\n roughness=1.0-parameters[0];\n metallic=parameters[1];\n fresnel0=parameters[2];\n#else\n emissive=Materials[int(materialIndex)].emissive;\n#endif\n#ifdef WIDTH\n gl_PointSize=width;\n#endif\n}\n",fragment="\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nvarying vec3 ViewPosition;\n#endif\nvarying vec3 Normal;\nvarying vec4 diffuse;\nvarying vec3 specular;\nvarying float roughness,metallic,fresnel0;\n\nfloat Roughness2;\nvec3 normal;\n\nstruct Light {\n vec3 direction;\n vec3 color;\n};\n\nuniform Light Lights[Nlights];\n\nfloat NDF_TRG(vec3 h)\n{\n float ndoth=max(dot(normal,h),0.0);\n float alpha2=Roughness2*Roughness2;\n float denom=ndoth*ndoth*(alpha2-1.0)+1.0;\n return denom != 0.0 ? alpha2/(denom*denom) : 0.0;\n}\n \nfloat GGX_Geom(vec3 v)\n{\n float ndotv=max(dot(v,normal),0.0);\n float ap=1.0+Roughness2;\n float k=0.125*ap*ap;\n return ndotv/((ndotv*(1.0-k))+k);\n}\n \nfloat Geom(vec3 v, vec3 l)\n{\n return GGX_Geom(v)*GGX_Geom(l);\n}\n \nfloat Fresnel(vec3 h, vec3 v, float fresnel0)\n{\n float a=1.0-max(dot(h,v),0.0);\n float b=a*a;\n return fresnel0+(1.0-fresnel0)*b*b*a;\n}\n \n// physical based shading using UE4 model.\nvec3 BRDF(vec3 viewDirection, vec3 lightDirection)\n{\n vec3 lambertian=diffuse.rgb;\n vec3 h=normalize(lightDirection+viewDirection);\n \n float omegain=max(dot(viewDirection,normal),0.0);\n float omegali=max(dot(lightDirection,normal),0.0);\n \n float D=NDF_TRG(h);\n float G=Geom(viewDirection,lightDirection);\n float F=Fresnel(h,viewDirection,fresnel0);\n \n float denom=4.0*omegain*omegali;\n float rawReflectance=denom > 0.0 ? (D*G)/denom : 0.0;\n \n vec3 dielectric=mix(lambertian,rawReflectance*specular,F);\n vec3 metal=rawReflectance*diffuse.rgb;\n \n return mix(dielectric,metal,metallic);\n}\n#endif\nvarying vec4 emissive;\n \nvoid main(void)\n{\n#if defined(NORMAL) && nlights > 0\n normal=normalize(Normal);\n normal=gl_FrontFacing ? normal : -normal;\n#ifdef ORTHOGRAPHIC\n vec3 viewDir=vec3(0.0,0.0,1.0);\n#else\n vec3 viewDir=-normalize(ViewPosition);\n#endif\n Roughness2=roughness*roughness;\n vec3 color=emissive.rgb;\n for(int i=0; i < nlights; ++i) {\n Light Li=Lights[i];\n vec3 L=Li.direction;\n float cosTheta=max(dot(normal,L),0.0);\n vec3 radiance=cosTheta*Li.color;\n color += BRDF(viewDir,L)*radiance;\n }\n gl_FragColor=vec4(color,diffuse.a);\n#else\n gl_FragColor=emissive;\n#endif\n}\n";!function(t,e){if("object"==typeof exports&&"object"==typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var i=e();for(var a in i)("object"==typeof exports?exports:t)[a]=i[a]}}("undefined"!=typeof self?self:this,(function(){return function(t){var e={};function i(a){if(e[a])return e[a].exports;var r=e[a]={i:a,l:!1,exports:{}};return t[a].call(r.exports,r,r.exports,i),r.l=!0,r.exports}return i.m=t,i.c=e,i.d=function(t,e,a){i.o(t,e)||Object.defineProperty(t,e,{configurable:!1,enumerable:!0,get:a})},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="",i(i.s=1)}([function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.setMatrixArrayType=function(t){e.ARRAY_TYPE=t},e.toRadian=function(t){return t*r},e.equals=function(t,e){return Math.abs(t-e)<=a*Math.max(1,Math.abs(t),Math.abs(e))};var a=e.EPSILON=1e-6;e.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,e.RANDOM=Math.random;var r=Math.PI/180},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.mat4=e.mat3=void 0;var a=n(i(2)),r=n(i(3));function n(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}e.mat3=a,e.mat4=r},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.create=function(){var t=new a.ARRAY_TYPE(9);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=1,t[5]=0,t[6]=0,t[7]=0,t[8]=1,t},e.fromMat4=function(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[4],t[4]=e[5],t[5]=e[6],t[6]=e[8],t[7]=e[9],t[8]=e[10],t},e.invert=function(t,e){var i=e[0],a=e[1],r=e[2],n=e[3],s=e[4],o=e[5],h=e[6],l=e[7],c=e[8],d=c*s-o*l,m=-c*n+o*h,f=l*n-s*h,u=i*d+a*m+r*f;if(!u)return null;return u=1/u,t[0]=d*u,t[1]=(-c*a+r*l)*u,t[2]=(o*a-r*s)*u,t[3]=m*u,t[4]=(c*i-r*h)*u,t[5]=(-o*i+r*n)*u,t[6]=f*u,t[7]=(-l*i+a*h)*u,t[8]=(s*i-a*n)*u,t};var a=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}(i(0))},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0}),e.create=function(){var t=new a.ARRAY_TYPE(16);return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.identity=function(t){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.invert=function(t,e){var i=e[0],a=e[1],r=e[2],n=e[3],s=e[4],o=e[5],h=e[6],l=e[7],c=e[8],d=e[9],m=e[10],f=e[11],u=e[12],p=e[13],v=e[14],g=e[15],x=i*o-a*s,w=i*h-r*s,M=i*l-n*s,b=a*h-r*o,S=a*l-n*o,P=r*l-n*h,A=c*p-d*u,y=c*v-m*u,T=c*g-f*u,R=d*v-m*p,D=d*g-f*p,I=m*g-f*v,z=x*I-w*D+M*R+b*T-S*y+P*A;if(!z)return null;return z=1/z,t[0]=(o*I-h*D+l*R)*z,t[1]=(r*D-a*I-n*R)*z,t[2]=(p*P-v*S+g*b)*z,t[3]=(m*S-d*P-f*b)*z,t[4]=(h*T-s*I-l*y)*z,t[5]=(i*I-r*T+n*y)*z,t[6]=(v*M-u*P-g*w)*z,t[7]=(c*P-m*M+f*w)*z,t[8]=(s*D-o*T+l*A)*z,t[9]=(a*T-i*D-n*A)*z,t[10]=(u*S-p*M+g*x)*z,t[11]=(d*M-c*S-f*x)*z,t[12]=(o*y-s*R-h*A)*z,t[13]=(i*R-a*y+r*A)*z,t[14]=(p*w-u*b-v*x)*z,t[15]=(c*b-d*w+m*x)*z,t},e.multiply=r,e.translate=function(t,e,i){var a=i[0],r=i[1],n=i[2],s=void 0,o=void 0,h=void 0,l=void 0,c=void 0,d=void 0,m=void 0,f=void 0,u=void 0,p=void 0,v=void 0,g=void 0;e===t?(t[12]=e[0]*a+e[4]*r+e[8]*n+e[12],t[13]=e[1]*a+e[5]*r+e[9]*n+e[13],t[14]=e[2]*a+e[6]*r+e[10]*n+e[14],t[15]=e[3]*a+e[7]*r+e[11]*n+e[15]):(s=e[0],o=e[1],h=e[2],l=e[3],c=e[4],d=e[5],m=e[6],f=e[7],u=e[8],p=e[9],v=e[10],g=e[11],t[0]=s,t[1]=o,t[2]=h,t[3]=l,t[4]=c,t[5]=d,t[6]=m,t[7]=f,t[8]=u,t[9]=p,t[10]=v,t[11]=g,t[12]=s*a+c*r+u*n+e[12],t[13]=o*a+d*r+p*n+e[13],t[14]=h*a+m*r+v*n+e[14],t[15]=l*a+f*r+g*n+e[15]);return t},e.rotate=function(t,e,i,r){var n,s,o,h,l,c,d,m,f,u,p,v,g,x,w,M,b,S,P,A,y,T,R,D,I=r[0],z=r[1],L=r[2],N=Math.sqrt(I*I+z*z+L*L);if(Math.abs(N)<a.EPSILON)return null;I*=N=1/N,z*=N,L*=N,n=Math.sin(i),s=Math.cos(i),o=1-s,h=e[0],l=e[1],c=e[2],d=e[3],m=e[4],f=e[5],u=e[6],p=e[7],v=e[8],g=e[9],x=e[10],w=e[11],M=I*I*o+s,b=z*I*o+L*n,S=L*I*o-z*n,P=I*z*o-L*n,A=z*z*o+s,y=L*z*o+I*n,T=I*L*o+z*n,R=z*L*o-I*n,D=L*L*o+s,t[0]=h*M+m*b+v*S,t[1]=l*M+f*b+g*S,t[2]=c*M+u*b+x*S,t[3]=d*M+p*b+w*S,t[4]=h*P+m*A+v*y,t[5]=l*P+f*A+g*y,t[6]=c*P+u*A+x*y,t[7]=d*P+p*A+w*y,t[8]=h*T+m*R+v*D,t[9]=l*T+f*R+g*D,t[10]=c*T+u*R+x*D,t[11]=d*T+p*R+w*D,e!==t&&(t[12]=e[12],t[13]=e[13],t[14]=e[14],t[15]=e[15]);return t},e.fromTranslation=function(t,e){return t[0]=1,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=1,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=1,t[11]=0,t[12]=e[0],t[13]=e[1],t[14]=e[2],t[15]=1,t},e.fromRotation=function(t,e,i){var r,n,s,o=i[0],h=i[1],l=i[2],c=Math.sqrt(o*o+h*h+l*l);if(Math.abs(c)<a.EPSILON)return null;return o*=c=1/c,h*=c,l*=c,r=Math.sin(e),n=Math.cos(e),s=1-n,t[0]=o*o*s+n,t[1]=h*o*s+l*r,t[2]=l*o*s-h*r,t[3]=0,t[4]=o*h*s-l*r,t[5]=h*h*s+n,t[6]=l*h*s+o*r,t[7]=0,t[8]=o*l*s+h*r,t[9]=h*l*s-o*r,t[10]=l*l*s+n,t[11]=0,t[12]=0,t[13]=0,t[14]=0,t[15]=1,t},e.frustum=function(t,e,i,a,r,n,s){var o=1/(i-e),h=1/(r-a),l=1/(n-s);return t[0]=2*n*o,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=2*n*h,t[6]=0,t[7]=0,t[8]=(i+e)*o,t[9]=(r+a)*h,t[10]=(s+n)*l,t[11]=-1,t[12]=0,t[13]=0,t[14]=s*n*2*l,t[15]=0,t},e.ortho=function(t,e,i,a,r,n,s){var o=1/(e-i),h=1/(a-r),l=1/(n-s);return t[0]=-2*o,t[1]=0,t[2]=0,t[3]=0,t[4]=0,t[5]=-2*h,t[6]=0,t[7]=0,t[8]=0,t[9]=0,t[10]=2*l,t[11]=0,t[12]=(e+i)*o,t[13]=(r+a)*h,t[14]=(s+n)*l,t[15]=1,t};var a=function(t){if(t&&t.__esModule)return t;var e={};if(null!=t)for(var i in t)Object.prototype.hasOwnProperty.call(t,i)&&(e[i]=t[i]);return e.default=t,e}(i(0));function r(t,e,i){var a=e[0],r=e[1],n=e[2],s=e[3],o=e[4],h=e[5],l=e[6],c=e[7],d=e[8],m=e[9],f=e[10],u=e[11],p=e[12],v=e[13],g=e[14],x=e[15],w=i[0],M=i[1],b=i[2],S=i[3];return t[0]=w*a+M*o+b*d+S*p,t[1]=w*r+M*h+b*m+S*v,t[2]=w*n+M*l+b*f+S*g,t[3]=w*s+M*c+b*u+S*x,w=i[4],M=i[5],b=i[6],S=i[7],t[4]=w*a+M*o+b*d+S*p,t[5]=w*r+M*h+b*m+S*v,t[6]=w*n+M*l+b*f+S*g,t[7]=w*s+M*c+b*u+S*x,w=i[8],M=i[9],b=i[10],S=i[11],t[8]=w*a+M*o+b*d+S*p,t[9]=w*r+M*h+b*m+S*v,t[10]=w*n+M*l+b*f+S*g,t[11]=w*s+M*c+b*u+S*x,w=i[12],M=i[13],b=i[14],S=i[15],t[12]=w*a+M*o+b*d+S*p,t[13]=w*r+M*h+b*m+S*v,t[14]=w*n+M*l+b*f+S*g,t[15]=w*s+M*c+b*u+S*x,t}}])}));let canvasWidth,canvasHeight,canvasWidth0,canvasHeight0,b,B,angle,Zoom0,zoom0,viewportmargin,zoomFactor,zoomPinchFactor,zoomPinchCap,zoomStep,shiftHoldDistance,shiftWaitTime,vibrateTime,embedded,canvas,gl,alpha,offscreen,context,maxMaterials,halfCanvasWidth,halfCanvasHeight,Zoom,maxViewportWidth,maxViewportHeight,P=[],Materials=[],Lights=[],Centers=[],Background=[1,1,1,1],absolute=!1,viewportshift=[0,0],nlights=0,Nmaterials=2,materials=[],pixel=.75,zoomRemeshFactor=1.5,FillFactor=.1;const windowTrim=10;let lastZoom,H,zmin,zmax,size2,ArcballFactor,third=1/3,rotMat=mat4.create(),projMat=mat4.create(),viewMat=mat4.create(),projViewMat=mat4.create(),normMat=mat3.create(),viewMat3=mat3.create(),cjMatInv=mat4.create(),T=mat4.create(),center={x:0,y:0,z:0},shift={x:0,y:0},viewParam={xmin:0,xmax:0,ymin:0,ymax:0,zmin:0,zmax:0},remesh=!0,wireframe=0,mouseDownOrTouchActive=!1,lastMouseX=null,lastMouseY=null,touchID=null,Positions=[],Normals=[],Colors=[],Indices=[];class Material{constructor(t,e,i,a,r,n){this.diffuse=t,this.emissive=e,this.specular=i,this.shininess=a,this.metallic=r,this.fresnel0=n}setUniform(t,e){let i=i=>gl.getUniformLocation(t,"Materials["+e+"]."+i);gl.uniform4fv(i("diffuse"),new Float32Array(this.diffuse)),gl.uniform4fv(i("emissive"),new Float32Array(this.emissive)),gl.uniform4fv(i("specular"),new Float32Array(this.specular)),gl.uniform4f(i("parameters"),this.shininess,this.metallic,this.fresnel0,0)}}let indexExt,TRIANGLES,material0Data,material1Data,materialData,colorData,transparentData,triangleData,materialIndex,enumPointLight=1,enumDirectionalLight=2;class Light{constructor(t,e){this.direction=t,this.color=e}setUniform(t,e){let i=i=>gl.getUniformLocation(t,"Lights["+e+"]."+i);gl.uniform3fv(i("direction"),new Float32Array(this.direction)),gl.uniform3fv(i("color"),new Float32Array(this.color))}}function initShaders(){let t=gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);maxMaterials=Math.floor((t-14)/4),Nmaterials=Math.min(Math.max(Nmaterials,Materials.length),maxMaterials),pixelShader=initShader(["WIDTH"]),materialShader=initShader(["NORMAL"]),colorShader=initShader(["NORMAL","COLOR"]),transparentShader=initShader(["NORMAL","COLOR","TRANSPARENT"])}function deleteShaders(){gl.deleteProgram(transparentShader),gl.deleteProgram(colorShader),gl.deleteProgram(materialShader),gl.deleteProgram(pixelShader)}function noGL(){gl||alert("Could not initialize WebGL")}function saveAttributes(){let t=window.top.document.asygl[alpha];t.gl=gl,t.nlights=Lights.length,t.Nmaterials=Nmaterials,t.maxMaterials=maxMaterials,t.pixelShader=pixelShader,t.materialShader=materialShader,t.colorShader=colorShader,t.transparentShader=transparentShader}function restoreAttributes(){let t=window.top.document.asygl[alpha];gl=t.gl,nlights=t.nlights,Nmaterials=t.Nmaterials,maxMaterials=t.maxMaterials,pixelShader=t.pixelShader,materialShader=t.materialShader,colorShader=t.colorShader,transparentShader=t.transparentShader}function initGL(){if(alpha=Background[3]<1,embedded){let t=window.top.document;null==t.asygl&&(t.asygl=Array(2)),context=canvas.getContext("2d"),offscreen=t.offscreen,offscreen||(offscreen=t.createElement("canvas"),t.offscreen=offscreen),t.asygl[alpha]&&t.asygl[alpha].gl?(restoreAttributes(),(Lights.length!=nlights||Math.min(Materials.length,maxMaterials)>Nmaterials)&&(initShaders(),saveAttributes())):(gl=offscreen.getContext("webgl",{alpha:alpha}),gl||noGL(),initShaders(),t.asygl[alpha]={},saveAttributes())}else gl=canvas.getContext("webgl",{alpha:alpha}),gl||noGL(),initShaders();indexExt=gl.getExtension("OES_element_index_uint"),TRIANGLES=gl.TRIANGLES,material0Data=new vertexBuffer(gl.POINTS),material1Data=new vertexBuffer(gl.LINES),materialData=new vertexBuffer,colorData=new vertexBuffer,transparentData=new vertexBuffer,triangleData=new vertexBuffer}function getShader(t,e,i,a=[]){let r=`#version 100\n#ifdef GL_FRAGMENT_PRECISION_HIGH\n precision highp float;\n#else\n precision mediump float;\n#endif\n #define nlights ${0==wireframe?Lights.length:0}\n\n const int Nlights=${Math.max(Lights.length,1)};\n\n #define Nmaterials ${Nmaterials}\n`;orthographic&&(r+="#define ORTHOGRAPHIC\n"),a.forEach(t=>r+="#define "+t+"\n");let n=t.createShader(i);return t.shaderSource(n,r+e),t.compileShader(n),t.getShaderParameter(n,t.COMPILE_STATUS)?n:(alert(t.getShaderInfoLog(n)),null)}function registerBuffer(t,e,i,a=gl.ARRAY_BUFFER){return t.length>0&&(0==e&&(e=gl.createBuffer(),i=!0),gl.bindBuffer(a,e),i&&gl.bufferData(a,t,gl.STATIC_DRAW)),e}function drawBuffer(t,e,i=t.indices){if(0==t.indices.length)return;let a=e!=pixelShader;setUniforms(t,e);let r=remesh||t.partial||!t.rendered;t.verticesBuffer=registerBuffer(new Float32Array(t.vertices),t.verticesBuffer,r),gl.vertexAttribPointer(positionAttribute,3,gl.FLOAT,!1,a?24:16,0),a&&Lights.length>0?gl.vertexAttribPointer(normalAttribute,3,gl.FLOAT,!1,24,12):pixel&&gl.vertexAttribPointer(widthAttribute,1,gl.FLOAT,!1,16,12),t.materialsBuffer=registerBuffer(new Int16Array(t.materialIndices),t.materialsBuffer,r),gl.vertexAttribPointer(materialAttribute,1,gl.SHORT,!1,2,0),e!=colorShader&&e!=transparentShader||(t.colorsBuffer=registerBuffer(new Uint8Array(t.colors),t.colorsBuffer,r),gl.vertexAttribPointer(colorAttribute,4,gl.UNSIGNED_BYTE,!0,0,0)),t.indicesBuffer=registerBuffer(indexExt?new Uint32Array(i):new Uint16Array(i),t.indicesBuffer,r,gl.ELEMENT_ARRAY_BUFFER),t.rendered=!0,gl.drawElements(a?wireframe?gl.LINES:t.type:gl.POINTS,i.length,indexExt?gl.UNSIGNED_INT:gl.UNSIGNED_SHORT,0)}class vertexBuffer{constructor(t){this.type=t||TRIANGLES,this.verticesBuffer=0,this.materialsBuffer=0,this.colorsBuffer=0,this.indicesBuffer=0,this.rendered=!1,this.partial=!1,this.clear()}clear(){this.vertices=[],this.materialIndices=[],this.colors=[],this.indices=[],this.nvertices=0,this.materials=[],this.materialTable=[]}vertex(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(materialIndex),this.nvertices++}Vertex(t,e,i=[0,0,0,0]){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.materialIndices.push(materialIndex),this.colors.push(i[0]),this.colors.push(i[1]),this.colors.push(i[2]),this.colors.push(i[3]),this.nvertices++}vertex0(t,e){return this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.vertices.push(e),this.materialIndices.push(materialIndex),this.nvertices++}iVertex(t,e,i,a=[0,0,0,0]){let r=6*t;this.vertices[r]=e[0],this.vertices[r+1]=e[1],this.vertices[r+2]=e[2],this.vertices[r+3]=i[0],this.vertices[r+4]=i[1],this.vertices[r+5]=i[2],this.materialIndices[t]=materialIndex;let n=4*t;this.colors[n]=a[0],this.colors[n+1]=a[1],this.colors[n+2]=a[2],this.colors[n+3]=a[3],this.indices.push(t)}append(t){append(this.vertices,t.vertices),append(this.materialIndices,t.materialIndices),append(this.colors,t.colors),appendOffset(this.indices,t.indices,this.nvertices),this.nvertices+=t.nvertices}}function append(t,e){let i=t.length,a=e.length;t.length+=a;for(let r=0;r<a;++r)t[i+r]=e[r]}function appendOffset(t,e,i){let a=t.length,r=e.length;t.length+=e.length;for(let n=0;n<r;++n)t[a+n]=e[n]+i}class Geometry{constructor(){this.data=new vertexBuffer,this.Onscreen=!1,this.m=[]}offscreen(t){let e=projViewMat,i=t[0],a=i[0],r=i[1],n=i[2],s=1/(e[3]*a+e[7]*r+e[11]*n+e[15]);this.x=this.X=(e[0]*a+e[4]*r+e[8]*n+e[12])*s,this.y=this.Y=(e[1]*a+e[5]*r+e[9]*n+e[13])*s;for(let i=1,a=t.length;i<a;++i){let a=t[i],r=a[0],n=a[1],s=a[2],o=1/(e[3]*r+e[7]*n+e[11]*s+e[15]),h=(e[0]*r+e[4]*n+e[8]*s+e[12])*o,l=(e[1]*r+e[5]*n+e[9]*s+e[13])*o;h<this.x?this.x=h:h>this.X&&(this.X=h),l<this.y?this.y=l:l>this.Y&&(this.Y=l)}return(this.X<-1.01||this.x>1.01||this.Y<-1.01||this.y>1.01)&&(this.Onscreen=!1,!0)}T(t){let e=this.c[0],i=this.c[1],a=this.c[2],r=t[0]-e,n=t[1]-i,s=t[2]-a;return[r*normMat[0]+n*normMat[3]+s*normMat[6]+e,r*normMat[1]+n*normMat[4]+s*normMat[7]+i,r*normMat[2]+n*normMat[5]+s*normMat[8]+a]}Tcorners(t,e){return[this.T(t),this.T([t[0],t[1],e[2]]),this.T([t[0],e[1],t[2]]),this.T([t[0],e[1],e[2]]),this.T([e[0],t[1],t[2]]),this.T([e[0],t[1],e[2]]),this.T([e[0],e[1],t[2]]),this.T(e)]}setMaterial(t,e){null==t.materialTable[this.MaterialIndex]&&(t.materials.length>=Nmaterials&&(t.partial=!0,e()),t.materialTable[this.MaterialIndex]=t.materials.length,t.materials.push(Materials[this.MaterialIndex])),materialIndex=t.materialTable[this.MaterialIndex]}render(){let t;if(this.setMaterialIndex(),0==this.CenterIndex?t=corners(this.Min,this.Max):(this.c=Centers[this.CenterIndex-1],t=this.Tcorners(this.Min,this.Max)),this.offscreen(t))return this.data.clear(),void this.notRendered();let e,i=this.controlpoints;if(0==this.CenterIndex){if(!remesh&&this.Onscreen)return void this.append();e=i}else{let t=i.length;e=Array(t);for(let a=0;a<t;++a)e[a]=this.T(i[a])}let a=orthographic?1:this.Min[2]/B[2],r=pixel*Math.hypot(a*(viewParam.xmax-viewParam.xmin),a*(viewParam.ymax-viewParam.ymin))/size2;this.res2=r*r,this.Epsilon=FillFactor*r,this.data.clear(),this.notRendered(),this.Onscreen=!0,this.process(e)}}class BezierPatch extends Geometry{constructor(t,e,i,a,r,n){super(),this.controlpoints=t,this.Min=a,this.Max=r,this.color=n,this.CenterIndex=e;let s=t.length;if(n){let t=n[0][3]+n[1][3]+n[2][3];this.transparent=16==s||4==s?t+n[3][3]<1020:t<765}else this.transparent=Materials[i].diffuse[3]<1;this.MaterialIndex=i,this.vertex=this.transparent?this.data.Vertex.bind(this.data):this.data.vertex.bind(this.data),this.L2norm(this.controlpoints)}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.color?this.setMaterial(colorData,drawColor):this.setMaterial(materialData,drawMaterial)}L2norm(t){let e=t[0];this.epsilon=0;let i=t.length;for(let a=1;a<i;++a)this.epsilon=Math.max(this.epsilon,abs2([t[a][0]-e[0],t[a][1]-e[1],t[a][2]-e[2]]));this.epsilon*=Number.EPSILON}processTriangle(t){let e=t[0],i=t[1],a=t[2],r=unit(cross([i[0]-e[0],i[1]-e[1],i[2]-e[2]],[a[0]-e[0],a[1]-e[1],a[2]-e[2]]));if(!this.offscreen([e,i,a])){let t,n,s;this.color?(t=this.data.Vertex(e,r,this.color[0]),n=this.data.Vertex(i,r,this.color[1]),s=this.data.Vertex(a,r,this.color[2])):(t=this.vertex(e,r),n=this.vertex(i,r),s=this.vertex(a,r)),0==wireframe?(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(s)):(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(n),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(t)),this.append()}}processQuad(t){let e=t[0],i=t[1],a=t[2],r=t[3],n=cross([i[0]-e[0],i[1]-e[1],i[2]-e[2]],[a[0]-i[0],a[1]-i[1],a[2]-i[2]]),s=cross([a[0]-r[0],a[1]-r[1],a[2]-r[2]],[r[0]-e[0],r[1]-e[1],r[2]-e[2]]),o=unit([n[0]+s[0],n[1]+s[1],n[2]+s[2]]);if(!this.offscreen([e,i,a,r])){let t,n,s,h;this.color?(t=this.data.Vertex(e,o,this.color[0]),n=this.data.Vertex(i,o,this.color[1]),s=this.data.Vertex(a,o,this.color[2]),h=this.data.Vertex(r,o,this.color[3])):(t=this.vertex(e,o),n=this.vertex(i,o),s=this.vertex(a,o),h=this.vertex(r,o)),0==wireframe?(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(s),this.data.indices.push(t),this.data.indices.push(s),this.data.indices.push(h)):(this.data.indices.push(t),this.data.indices.push(n),this.data.indices.push(n),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(h),this.data.indices.push(h),this.data.indices.push(t)),this.append()}}curve(t,e,i,a,r){new BezierCurve([t[e],t[i],t[a],t[r]],0,materialIndex,this.Min,this.Max).render()}process(t){if(this.transparent&&1!=wireframe&&(materialIndex=this.color?-1-materialIndex:1+materialIndex),10==t.length)return this.process3(t);if(3==t.length)return this.processTriangle(t);if(4==t.length)return this.processQuad(t);if(1==wireframe)return this.curve(t,0,4,8,12),this.curve(t,12,13,14,15),this.curve(t,15,11,7,3),void this.curve(t,3,2,1,0);let e=t[0],i=t[3],a=t[12],r=t[15],n=this.normal(i,t[2],t[1],e,t[4],t[8],a);abs2(n)<this.epsilon&&(n=this.normal(i,t[2],t[1],e,t[13],t[14],r),abs2(n)<this.epsilon&&(n=this.normal(r,t[11],t[7],i,t[4],t[8],a)));let s=this.normal(e,t[4],t[8],a,t[13],t[14],r);abs2(s)<this.epsilon&&(s=this.normal(e,t[4],t[8],a,t[11],t[7],i),abs2(s)<this.epsilon&&(s=this.normal(i,t[2],t[1],e,t[13],t[14],r)));let o=this.normal(a,t[13],t[14],r,t[11],t[7],i);abs2(o)<this.epsilon&&(o=this.normal(a,t[13],t[14],r,t[2],t[1],e),abs2(o)<this.epsilon&&(o=this.normal(e,t[4],t[8],a,t[11],t[7],i)));let h=this.normal(r,t[11],t[7],i,t[2],t[1],e);if(abs2(h)<this.epsilon&&(h=this.normal(r,t[11],t[7],i,t[4],t[8],a),abs2(h)<this.epsilon&&(h=this.normal(a,t[13],t[14],r,t[2],t[1],e))),this.color){let l=this.color[0],c=this.color[1],d=this.color[2],m=this.color[3],f=this.data.Vertex(e,n,l),u=this.data.Vertex(a,s,c),p=this.data.Vertex(r,o,d),v=this.data.Vertex(i,h,m);this.Render(t,f,u,p,v,e,a,r,i,!1,!1,!1,!1,l,c,d,m)}else{let l=this.vertex(e,n),c=this.vertex(a,s),d=this.vertex(r,o),m=this.vertex(i,h);this.Render(t,l,c,d,m,e,a,r,i,!1,!1,!1,!1)}this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):this.color?colorData.append(this.data):materialData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:this.color?colorData.rendered=!1:materialData.rendered=!1}Render(t,e,i,a,r,n,s,o,h,l,c,d,m,f,u,p,v){let g=this.Distance(t);if(g[0]<this.res2&&g[1]<this.res2)this.offscreen([n,s,o])||(0==wireframe?(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a))),this.offscreen([n,o,h])||(0==wireframe?(this.data.indices.push(e),this.data.indices.push(a),this.data.indices.push(r)):(this.data.indices.push(a),this.data.indices.push(r),this.data.indices.push(r),this.data.indices.push(e)));else{if(this.offscreen(t))return;let x=t[0],w=t[3],M=t[12],b=t[15];if(g[0]<this.res2){let g=new Split3(x,t[1],t[2],w),S=new Split3(t[4],t[5],t[6],t[7]),P=new Split3(t[8],t[9],t[10],t[11]),A=new Split3(M,t[13],t[14],b),y=[x,g.m0,g.m3,g.m5,t[4],S.m0,S.m3,S.m5,t[8],P.m0,P.m3,P.m5,M,A.m0,A.m3,A.m5],T=[g.m5,g.m4,g.m2,w,S.m5,S.m4,S.m2,t[7],P.m5,P.m4,P.m2,t[11],A.m5,A.m4,A.m2,b],R=this.normal(y[12],y[13],y[14],y[15],y[11],y[7],y[3]);abs2(R)<=this.epsilon&&(R=this.normal(y[12],y[13],y[14],y[15],y[2],y[1],y[0]),abs2(R)<=this.epsilon&&(R=this.normal(y[0],y[4],y[8],y[12],y[11],y[7],y[3])));let D=this.normal(T[3],T[2],T[1],T[0],T[4],T[8],T[12]);abs2(D)<=this.epsilon&&(D=this.normal(T[3],T[2],T[1],T[0],T[13],T[14],T[15]),abs2(D)<=this.epsilon&&(D=this.normal(T[15],T[11],T[7],T[3],T[4],T[8],T[12])));let I=this.Epsilon,z=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,t[13],t[14],b)<this.res2){let t=unit(this.differential(T[12],T[8],T[4],T[0]));z=[z[0]-I*t[0],z[1]-I*t[1],z[2]-I*t[2]]}else z=y[15];let L=[.5*(h[0]+n[0]),.5*(h[1]+n[1]),.5*(h[2]+n[2])];if(!m)if(m=Straightness(x,t[1],t[2],w)<this.res2){let t=unit(this.differential(y[3],y[7],y[11],y[15]));L=[L[0]-I*t[0],L[1]-I*t[1],L[2]-I*t[2]]}else L=T[0];if(f){let t=Array(4),g=Array(4);for(let e=0;e<4;++e)t[e]=.5*(u[e]+p[e]),g[e]=.5*(v[e]+f[e]);let x=this.data.Vertex(z,R,t),w=this.data.Vertex(L,D,g);this.Render(y,e,i,x,w,n,s,z,L,l,c,!1,m,f,u,t,g),this.Render(T,w,x,a,r,L,z,o,h,!1,c,d,m,g,t,p,v)}else{let t=this.vertex(z,R),f=this.vertex(L,D);this.Render(y,e,i,t,f,n,s,z,L,l,c,!1,m),this.Render(T,f,t,a,r,L,z,o,h,!1,c,d,m)}return}if(g[1]<this.res2){let g=new Split3(x,t[4],t[8],M),S=new Split3(t[1],t[5],t[9],t[13]),P=new Split3(t[2],t[6],t[10],t[14]),A=new Split3(w,t[7],t[11],b),y=[x,t[1],t[2],w,g.m0,S.m0,P.m0,A.m0,g.m3,S.m3,P.m3,A.m3,g.m5,S.m5,P.m5,A.m5],T=[g.m5,S.m5,P.m5,A.m5,g.m4,S.m4,P.m4,A.m4,g.m2,S.m2,P.m2,A.m2,M,t[13],t[14],b],R=this.normal(y[0],y[4],y[8],y[12],y[13],y[14],y[15]);abs2(R)<=this.epsilon&&(R=this.normal(y[0],y[4],y[8],y[12],y[11],y[7],y[3]),abs2(R)<=this.epsilon&&(R=this.normal(y[3],y[2],y[1],y[0],y[13],y[14],y[15])));let D=this.normal(T[15],T[11],T[7],T[3],T[2],T[1],T[0]);abs2(D)<=this.epsilon&&(D=this.normal(T[15],T[11],T[7],T[3],T[4],T[8],T[12]),abs2(D)<=this.epsilon&&(D=this.normal(T[12],T[13],T[14],T[15],T[2],T[1],T[0])));let I=this.Epsilon,z=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])];if(!l)if(l=Straightness(x,t[4],t[8],M)<this.res2){let t=unit(this.differential(T[0],T[1],T[2],T[3]));z=[z[0]-I*t[0],z[1]-I*t[1],z[2]-I*t[2]]}else z=y[12];let L=[.5*(o[0]+h[0]),.5*(o[1]+h[1]),.5*(o[2]+h[2])];if(!d)if(d=Straightness(b,t[11],t[7],w)<this.res2){let t=unit(this.differential(y[15],y[14],y[13],y[12]));L=[L[0]-I*t[0],L[1]-I*t[1],L[2]-I*t[2]]}else L=T[3];if(f){let t=Array(4),g=Array(4);for(let e=0;e<4;++e)t[e]=.5*(f[e]+u[e]),g[e]=.5*(p[e]+v[e]);let x=this.data.Vertex(z,R,t),w=this.data.Vertex(L,D,g);this.Render(y,e,x,w,r,n,z,L,h,l,!1,d,m,f,t,g,v),this.Render(T,x,i,a,w,z,s,o,L,l,c,d,!1,t,u,p,g)}else{let t=this.vertex(z,R),f=this.vertex(L,D);this.Render(y,e,t,f,r,n,z,L,h,l,!1,d,m),this.Render(T,t,i,a,f,z,s,o,L,l,c,d,!1)}return}let S=new Split3(x,t[1],t[2],w),P=new Split3(t[4],t[5],t[6],t[7]),A=new Split3(t[8],t[9],t[10],t[11]),y=new Split3(M,t[13],t[14],b),T=new Split3(x,t[4],t[8],M),R=new Split3(S.m0,P.m0,A.m0,y.m0),D=new Split3(S.m3,P.m3,A.m3,y.m3),I=new Split3(S.m5,P.m5,A.m5,y.m5),z=new Split3(S.m4,P.m4,A.m4,y.m4),L=new Split3(S.m2,P.m2,A.m2,y.m2),N=new Split3(w,t[7],t[11],b),E=[x,S.m0,S.m3,S.m5,T.m0,R.m0,D.m0,I.m0,T.m3,R.m3,D.m3,I.m3,T.m5,R.m5,D.m5,I.m5],O=[T.m5,R.m5,D.m5,I.m5,T.m4,R.m4,D.m4,I.m4,T.m2,R.m2,D.m2,I.m2,M,y.m0,y.m3,y.m5],V=[I.m5,z.m5,L.m5,N.m5,I.m4,z.m4,L.m4,N.m4,I.m2,z.m2,L.m2,N.m2,y.m5,y.m4,y.m2,b],C=[S.m5,S.m4,S.m2,w,I.m0,z.m0,L.m0,N.m0,I.m3,z.m3,L.m3,N.m3,I.m5,z.m5,L.m5,N.m5],B=E[15],H=this.normal(E[0],E[4],E[8],E[12],E[13],E[14],E[15]);abs2(H)<this.epsilon&&(H=this.normal(E[0],E[4],E[8],E[12],E[11],E[7],E[3]),abs2(H)<this.epsilon&&(H=this.normal(E[3],E[2],E[1],E[0],E[13],E[14],E[15])));let _=this.normal(O[12],O[13],O[14],O[15],O[11],O[7],O[3]);abs2(_)<this.epsilon&&(_=this.normal(O[12],O[13],O[14],O[15],O[2],O[1],O[0]),abs2(_)<this.epsilon&&(_=this.normal(O[0],O[4],O[8],O[12],O[11],O[7],O[3])));let F=this.normal(V[15],V[11],V[7],V[3],V[2],V[1],V[0]);abs2(F)<this.epsilon&&(F=this.normal(V[15],V[11],V[7],V[3],V[4],V[8],V[12]),abs2(F)<this.epsilon&&(F=this.normal(V[12],V[13],V[14],V[15],V[2],V[1],V[0])));let G=this.normal(C[3],C[2],C[1],C[0],C[4],C[8],C[12]);abs2(G)<this.epsilon&&(G=this.normal(C[3],C[2],C[1],C[0],C[13],C[14],C[15]),abs2(G)<this.epsilon&&(G=this.normal(C[15],C[11],C[7],C[3],C[4],C[8],C[12])));let W=this.normal(V[3],V[2],V[1],B,V[4],V[8],V[12]),U=this.Epsilon,Z=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])];if(!l)if(l=Straightness(x,t[4],t[8],M)<this.res2){let t=unit(this.differential(O[0],O[1],O[2],O[3]));Z=[Z[0]-U*t[0],Z[1]-U*t[1],Z[2]-U*t[2]]}else Z=E[12];let j=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,t[13],t[14],b)<this.res2){let t=unit(this.differential(V[12],V[8],V[4],V[0]));j=[j[0]-U*t[0],j[1]-U*t[1],j[2]-U*t[2]]}else j=O[15];let k=[.5*(o[0]+h[0]),.5*(o[1]+h[1]),.5*(o[2]+h[2])];if(!d)if(d=Straightness(b,t[11],t[7],w)<this.res2){let t=unit(this.differential(C[15],C[14],C[13],C[12]));k=[k[0]-U*t[0],k[1]-U*t[1],k[2]-U*t[2]]}else k=V[3];let Y=[.5*(h[0]+n[0]),.5*(h[1]+n[1]),.5*(h[2]+n[2])];if(!m)if(m=Straightness(x,t[1],t[2],w)<this.res2){let t=unit(this.differential(E[3],E[7],E[11],E[15]));Y=[Y[0]-U*t[0],Y[1]-U*t[1],Y[2]-U*t[2]]}else Y=C[0];if(f){let t=Array(4),g=Array(4),x=Array(4),w=Array(4),M=Array(4);for(let e=0;e<4;++e)t[e]=.5*(f[e]+u[e]),g[e]=.5*(u[e]+p[e]),x[e]=.5*(p[e]+v[e]),w[e]=.5*(v[e]+f[e]),M[e]=.5*(t[e]+x[e]);let b=this.data.Vertex(Z,H,t),S=this.data.Vertex(j,_,g),P=this.data.Vertex(k,F,x),A=this.data.Vertex(Y,G,w),y=this.data.Vertex(B,W,M);this.Render(E,e,b,y,A,n,Z,B,Y,l,!1,!1,m,f,t,M,w),this.Render(O,b,i,S,y,Z,s,j,B,l,c,!1,!1,t,u,g,M),this.Render(V,y,S,a,P,B,j,o,k,!1,c,d,!1,M,g,p,x),this.Render(C,A,y,P,r,Y,B,k,h,!1,!1,d,m,w,M,x,v)}else{let t=this.vertex(Z,H),f=this.vertex(j,_),u=this.vertex(k,F),p=this.vertex(Y,G),v=this.vertex(B,W);this.Render(E,e,t,v,p,n,Z,B,Y,l,!1,!1,m),this.Render(O,t,i,f,v,Z,s,j,B,l,c,!1,!1),this.Render(V,v,f,a,u,B,j,o,k,!1,c,d,!1),this.Render(C,p,v,u,r,Y,B,k,h,!1,!1,d,m)}}}process3(t){if(1==wireframe)return this.curve(t,0,1,3,6),this.curve(t,6,7,8,9),void this.curve(t,9,5,2,0);let e=t[0],i=t[6],a=t[9],r=this.normal(a,t[5],t[2],e,t[1],t[3],i),n=this.normal(e,t[1],t[3],i,t[7],t[8],a),s=this.normal(i,t[7],t[8],a,t[5],t[2],e);if(this.color){let o=this.color[0],h=this.color[1],l=this.color[2],c=this.data.Vertex(e,r,o),d=this.data.Vertex(i,n,h),m=this.data.Vertex(a,s,l);this.Render3(t,c,d,m,e,i,a,!1,!1,!1,o,h,l)}else{let o=this.vertex(e,r),h=this.vertex(i,n),l=this.vertex(a,s);this.Render3(t,o,h,l,e,i,a,!1,!1,!1)}this.data.indices.length>0&&this.append()}Render3(t,e,i,a,r,n,s,o,h,l,c,d,m){if(this.Distance3(t)<this.res2)this.offscreen([r,n,s])||(0==wireframe?(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(e),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a),this.data.indices.push(a),this.data.indices.push(e)));else{if(this.offscreen(t))return;let f=t[0],u=t[1],p=t[2],v=t[3],g=t[4],x=t[5],w=t[6],M=t[7],b=t[8],S=t[9],P=[.5*(S[0]+x[0]),.5*(S[1]+x[1]),.5*(S[2]+x[2])],A=[.5*(S[0]+b[0]),.5*(S[1]+b[1]),.5*(S[2]+b[2])],y=[.5*(x[0]+p[0]),.5*(x[1]+p[1]),.5*(x[2]+p[2])],T=[.5*(b[0]+g[0]),.5*(b[1]+g[1]),.5*(b[2]+g[2])],R=[.5*(b[0]+M[0]),.5*(b[1]+M[1]),.5*(b[2]+M[2])],D=[.5*(p[0]+g[0]),.5*(p[1]+g[1]),.5*(p[2]+g[2])],I=[.5*(p[0]+f[0]),.5*(p[1]+f[1]),.5*(p[2]+f[2])],z=[.5*(g[0]+v[0]),.5*(g[1]+v[1]),.5*(g[2]+v[2])],L=[.5*(M[0]+w[0]),.5*(M[1]+w[1]),.5*(M[2]+w[2])],N=[.5*(f[0]+u[0]),.5*(f[1]+u[1]),.5*(f[2]+u[2])],E=[.5*(u[0]+v[0]),.5*(u[1]+v[1]),.5*(u[2]+v[2])],O=[.5*(v[0]+w[0]),.5*(v[1]+w[1]),.5*(v[2]+w[2])],V=[.5*(P[0]+y[0]),.5*(P[1]+y[1]),.5*(P[2]+y[2])],C=[.5*(A[0]+R[0]),.5*(A[1]+R[1]),.5*(A[2]+R[2])],B=[.5*(y[0]+I[0]),.5*(y[1]+I[1]),.5*(y[2]+I[2])],H=[.5*T[0]+.25*(g[0]+u[0]),.5*T[1]+.25*(g[1]+u[1]),.5*T[2]+.25*(g[2]+u[2])],_=[.5*(R[0]+L[0]),.5*(R[1]+L[1]),.5*(R[2]+L[2])],F=[.5*D[0]+.25*(g[0]+M[0]),.5*D[1]+.25*(g[1]+M[1]),.5*D[2]+.25*(g[2]+M[2])],G=[.25*(x[0]+g[0])+.5*z[0],.25*(x[1]+g[1])+.5*z[1],.25*(x[2]+g[2])+.5*z[2]],W=[.5*(N[0]+E[0]),.5*(N[1]+E[1]),.5*(N[2]+E[2])],U=[.5*(E[0]+O[0]),.5*(E[1]+O[1]),.5*(E[2]+O[2])],Z=[.5*(F[0]+W[0]),.5*(F[1]+W[1]),.5*(F[2]+W[2])],j=[.5*(F[0]+U[0]),.5*(F[1]+U[1]),.5*(F[2]+U[2])],k=[.5*(W[0]+U[0]),.5*(W[1]+U[1]),.5*(W[2]+U[2])],Y=[.5*(G[0]+_[0]),.5*(G[1]+_[1]),.5*(G[2]+_[2])],X=[.5*(C[0]+G[0]),.5*(C[1]+G[1]),.5*(C[2]+G[2])],q=[.5*(C[0]+_[0]),.5*(C[1]+_[1]),.5*(C[2]+_[2])],K=[.5*(V[0]+H[0]),.5*(V[1]+H[1]),.5*(V[2]+H[2])],$=[.5*(B[0]+H[0]),.5*(B[1]+H[1]),.5*(B[2]+H[2])],Q=[.5*(V[0]+B[0]),.5*(V[1]+B[1]),.5*(V[2]+B[2])],J=[f,N,I,W,[.5*(D[0]+N[0]),.5*(D[1]+N[1]),.5*(D[2]+N[2])],B,k,Z,$,Q],tt=[k,U,j,O,[.5*(z[0]+L[0]),.5*(z[1]+L[1]),.5*(z[2]+L[2])],Y,w,L,_,q],et=[Q,K,V,X,[.5*(P[0]+T[0]),.5*(P[1]+T[1]),.5*(P[2]+T[2])],P,q,C,A,S],it=[q,X,Y,K,[.25*(y[0]+R[0]+E[0]+g[0]),.25*(y[1]+R[1]+E[1]+g[1]),.25*(y[2]+R[2]+E[2]+g[2])],j,Q,$,Z,k],at=this.normal(k,j,Y,q,X,K,Q),rt=this.normal(q,X,K,Q,$,Z,k),nt=this.normal(Q,$,Z,k,j,Y,q),st=this.Epsilon,ot=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])];if(!o)if(o=Straightness(w,M,b,S)<this.res2){let t=unit(this.sumdifferential(it[0],it[2],it[5],it[9],it[1],it[3],it[6]));ot=[ot[0]-st*t[0],ot[1]-st*t[1],ot[2]-st*t[2]]}else ot=q;let ht=[.5*(s[0]+r[0]),.5*(s[1]+r[1]),.5*(s[2]+r[2])];if(!h)if(h=Straightness(f,p,x,S)<this.res2){let t=unit(this.sumdifferential(it[6],it[3],it[1],it[0],it[7],it[8],it[9]));ht=[ht[0]-st*t[0],ht[1]-st*t[1],ht[2]-st*t[2]]}else ht=Q;let lt=[.5*(r[0]+n[0]),.5*(r[1]+n[1]),.5*(r[2]+n[2])];if(!l)if(l=Straightness(f,u,v,w)<this.res2){let t=unit(this.sumdifferential(it[9],it[8],it[7],it[6],it[5],it[2],it[0]));lt=[lt[0]-st*t[0],lt[1]-st*t[1],lt[2]-st*t[2]]}else lt=k;if(c){let t=Array(4),f=Array(4),u=Array(4);for(let e=0;e<4;++e)t[e]=.5*(d[e]+m[e]),f[e]=.5*(m[e]+c[e]),u[e]=.5*(c[e]+d[e]);let p=this.data.Vertex(ot,at,t),v=this.data.Vertex(ht,rt,f),g=this.data.Vertex(lt,nt,u);this.Render3(J,e,g,v,r,lt,ht,!1,h,l,c,u,f),this.Render3(tt,g,i,p,lt,n,ot,o,!1,l,u,d,t),this.Render3(et,v,p,a,ht,ot,s,o,h,!1,f,t,m),this.Render3(it,p,v,g,ot,ht,lt,!1,!1,!1,t,f,u)}else{let t=this.vertex(ot,at),c=this.vertex(ht,rt),d=this.vertex(lt,nt);this.Render3(J,e,d,c,r,lt,ht,!1,h,l),this.Render3(tt,d,i,t,lt,n,ot,o,!1,l),this.Render3(et,c,t,a,ht,ot,s,o,h,!1),this.Render3(it,t,c,d,ot,ht,lt,!1,!1,!1)}}}Distance(t){let e=t[0],i=t[3],a=t[12],r=t[15],n=Flatness(e,a,i,r);n=Math.max(Straightness(e,t[4],t[8],a)),n=Math.max(n,Straightness(t[1],t[5],t[9],t[13])),n=Math.max(n,Straightness(i,t[7],t[11],r)),n=Math.max(n,Straightness(t[2],t[6],t[10],t[14]));let s=Flatness(e,i,a,r);return s=Math.max(s,Straightness(e,t[1],t[2],i)),s=Math.max(s,Straightness(t[4],t[5],t[6],t[7])),s=Math.max(s,Straightness(t[8],t[9],t[10],t[11])),s=Math.max(s,Straightness(a,t[13],t[14],r)),[n,s]}Distance3(t){let e=t[0],i=t[4],a=t[6],r=t[9],n=abs2([(e[0]+a[0]+r[0])*third-i[0],(e[1]+a[1]+r[1])*third-i[1],(e[2]+a[2]+r[2])*third-i[2]]);return n=Math.max(n,Straightness(e,t[1],t[3],a)),n=Math.max(n,Straightness(e,t[2],t[5],r)),Math.max(n,Straightness(a,t[7],t[8],r))}differential(t,e,i,a){let r=[3*(e[0]-t[0]),3*(e[1]-t[1]),3*(e[2]-t[2])];return abs2(r)>this.epsilon?r:(r=bezierPP(t,e,i),abs2(r)>this.epsilon?r:bezierPPP(t,e,i,a))}sumdifferential(t,e,i,a,r,n,s){let o=this.differential(t,e,i,a),h=this.differential(t,r,n,s);return[o[0]+h[0],o[1]+h[1],o[2]+h[2]]}normal(t,e,i,a,r,n,s){let o=3*(r[0]-a[0]),h=3*(r[1]-a[1]),l=3*(r[2]-a[2]),c=3*(i[0]-a[0]),d=3*(i[1]-a[1]),m=3*(i[2]-a[2]),f=[h*m-l*d,l*c-o*m,o*d-h*c];if(abs2(f)>this.epsilon)return f;let u=[c,d,m],p=[o,h,l],v=bezierPP(a,i,e),g=bezierPP(a,r,n),x=cross(g,u),w=cross(p,v);if(f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon)return f;let M=bezierPPP(a,i,e,t),b=bezierPPP(a,r,n,s);x=cross(p,M),w=cross(b,u);let S=cross(g,v);return f=[x[0]+w[0]+S[0],x[1]+w[1]+S[1],x[2]+w[2]+S[2]],abs2(f)>this.epsilon?f:(x=cross(b,v),w=cross(g,M),f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon?f:cross(b,M))}}class BezierCurve extends Geometry{constructor(t,e,i,a,r){super(),this.controlpoints=t,this.Min=a,this.Max=r,this.CenterIndex=e,this.MaterialIndex=i}setMaterialIndex(){this.setMaterial(material1Data,drawMaterial1)}processLine(t){let e=t[0],i=t[1];if(!this.offscreen([e,i])){let t=[0,0,1];this.data.indices.push(this.data.vertex(e,t)),this.data.indices.push(this.data.vertex(i,t)),this.append()}}process(t){if(2==t.length)return this.processLine(t);let e=t[0],i=t[1],a=t[2],r=t[3],n=this.normal(bezierP(e,i),bezierPP(e,i,a)),s=this.normal(bezierP(a,r),bezierPP(r,a,i)),o=this.data.vertex(e,n),h=this.data.vertex(r,s);this.Render(t,o,h),this.data.indices.length>0&&this.append()}append(){material1Data.append(this.data)}notRendered(){material1Data.rendered=!1}Render(t,e,i){let a=t[0],r=t[1],n=t[2],s=t[3];if(Straightness(a,r,n,s)<this.res2)this.offscreen([a,s])||(this.data.indices.push(e),this.data.indices.push(i));else{if(this.offscreen(t))return;let o=[.5*(a[0]+r[0]),.5*(a[1]+r[1]),.5*(a[2]+r[2])],h=[.5*(r[0]+n[0]),.5*(r[1]+n[1]),.5*(r[2]+n[2])],l=[.5*(n[0]+s[0]),.5*(n[1]+s[1]),.5*(n[2]+s[2])],c=[.5*(o[0]+h[0]),.5*(o[1]+h[1]),.5*(o[2]+h[2])],d=[.5*(h[0]+l[0]),.5*(h[1]+l[1]),.5*(h[2]+l[2])],m=[.5*(c[0]+d[0]),.5*(c[1]+d[1]),.5*(c[2]+d[2])],f=[a,o,c,m],u=[m,d,l,s],p=this.normal(bezierPh(a,r,n,s),bezierPPh(a,r,n,s)),v=this.data.vertex(m,p);this.Render(f,e,v),this.Render(u,v,i)}}normal(t,e){let i=dot(t,t),a=dot(t,e);return[i*e[0]-a*t[0],i*e[1]-a*t[1],i*e[2]-a*t[2]]}}class Pixel extends Geometry{constructor(t,e,i,a,r){super(),this.controlpoint=t,this.width=e,this.CenterIndex=0,this.MaterialIndex=i,this.Min=a,this.Max=r}setMaterialIndex(){this.setMaterial(material0Data,drawMaterial0)}process(t){this.data.indices.push(this.data.vertex0(this.controlpoint,this.width)),this.append()}append(){material0Data.append(this.data)}notRendered(){material0Data.rendered=!1}}class Triangles extends Geometry{constructor(t,e,i){super(),this.CenterIndex=0,this.MaterialIndex=t,this.Min=e,this.Max=i,this.Positions=Positions,this.Normals=Normals,this.Colors=Colors,this.Indices=Indices,Positions=[],Normals=[],Colors=[],Indices=[],this.transparent=Materials[t].diffuse[3]<1}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.setMaterial(triangleData,drawTriangle)}process(t){materialIndex=this.Colors.length>0?-1-materialIndex:1+materialIndex;for(let t=0,e=this.Indices.length;t<e;++t){let e=this.Indices[t],i=e[0],a=this.Positions[i[0]],r=this.Positions[i[1]],n=this.Positions[i[2]];if(!this.offscreen([a,r,n])){let t=e.length>1?e[1]:i;if(t&&0!=t.length||(t=i),this.Colors.length>0){let s=e.length>2?e[2]:i;s&&0!=s.length||(s=i);let o=this.Colors[s[0]],h=this.Colors[s[1]],l=this.Colors[s[2]];this.transparent|=o[3]+h[3]+l[3]<765,0==wireframe?(this.data.iVertex(i[0],a,this.Normals[t[0]],o),this.data.iVertex(i[1],r,this.Normals[t[1]],h),this.data.iVertex(i[2],n,this.Normals[t[2]],l)):(this.data.iVertex(i[0],a,this.Normals[t[0]],o),this.data.iVertex(i[1],r,this.Normals[t[1]],h),this.data.iVertex(i[1],r,this.Normals[t[1]],h),this.data.iVertex(i[2],n,this.Normals[t[2]],l),this.data.iVertex(i[2],n,this.Normals[t[2]],l),this.data.iVertex(i[0],a,this.Normals[t[0]],o))}else 0==wireframe?(this.data.iVertex(i[0],a,this.Normals[t[0]]),this.data.iVertex(i[1],r,this.Normals[t[1]]),this.data.iVertex(i[2],n,this.Normals[t[2]])):(this.data.iVertex(i[0],a,this.Normals[t[0]]),this.data.iVertex(i[1],r,this.Normals[t[1]]),this.data.iVertex(i[1],r,this.Normals[t[1]]),this.data.iVertex(i[2],n,this.Normals[t[2]]),this.data.iVertex(i[2],n,this.Normals[t[2]]),this.data.iVertex(i[0],a,this.Normals[t[0]]))}}this.data.nvertices=this.Positions.length,this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):triangleData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:triangleData.rendered=!1}}function redraw(){initProjection(),setProjection(),remesh=!0,draw()}function home(){mat4.identity(rotMat),redraw()}let positionAttribute=0,normalAttribute=1,materialAttribute=2,colorAttribute=3,widthAttribute=4;function initShader(t=[]){let e=getShader(gl,vertex,gl.VERTEX_SHADER,t),i=getShader(gl,fragment,gl.FRAGMENT_SHADER,t),a=gl.createProgram();return gl.attachShader(a,e),gl.attachShader(a,i),gl.bindAttribLocation(a,positionAttribute,"position"),gl.bindAttribLocation(a,normalAttribute,"normal"),gl.bindAttribLocation(a,materialAttribute,"materialIndex"),gl.bindAttribLocation(a,colorAttribute,"color"),gl.bindAttribLocation(a,widthAttribute,"width"),gl.linkProgram(a),gl.getProgramParameter(a,gl.LINK_STATUS)||alert("Could not initialize shaders"),a}class Split3{constructor(t,e,i,a){this.m0=[.5*(t[0]+e[0]),.5*(t[1]+e[1]),.5*(t[2]+e[2])];let r=.5*(e[0]+i[0]),n=.5*(e[1]+i[1]),s=.5*(e[2]+i[2]);this.m2=[.5*(i[0]+a[0]),.5*(i[1]+a[1]),.5*(i[2]+a[2])],this.m3=[.5*(this.m0[0]+r),.5*(this.m0[1]+n),.5*(this.m0[2]+s)],this.m4=[.5*(r+this.m2[0]),.5*(n+this.m2[1]),.5*(s+this.m2[2])],this.m5=[.5*(this.m3[0]+this.m4[0]),.5*(this.m3[1]+this.m4[1]),.5*(this.m3[2]+this.m4[2])]}}function unit(t){let e=1/(Math.sqrt(t[0]*t[0]+t[1]*t[1]+t[2]*t[2])||1);return[t[0]*e,t[1]*e,t[2]*e]}function abs2(t){return t[0]*t[0]+t[1]*t[1]+t[2]*t[2]}function dot(t,e){return t[0]*e[0]+t[1]*e[1]+t[2]*e[2]}function cross(t,e){return[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]]}function bezierP(t,e){return[e[0]-t[0],e[1]-t[1],e[2]-t[2]]}function bezierPP(t,e,i){return[3*(t[0]+i[0])-6*e[0],3*(t[1]+i[1])-6*e[1],3*(t[2]+i[2])-6*e[2]]}function bezierPPP(t,e,i,a){return[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])]}function bezierPh(t,e,i,a){return[i[0]+a[0]-t[0]-e[0],i[1]+a[1]-t[1]-e[1],i[2]+a[2]-t[2]-e[2]]}function bezierPPh(t,e,i,a){return[3*t[0]-5*e[0]+i[0]+a[0],3*t[1]-5*e[1]+i[1]+a[1],3*t[2]-5*e[2]+i[2]+a[2]]}function Straightness(t,e,i,a){let r=[third*(a[0]-t[0]),third*(a[1]-t[1]),third*(a[2]-t[2])];return Math.max(abs2([e[0]-r[0]-t[0],e[1]-r[1]-t[1],e[2]-r[2]-t[2]]),abs2([a[0]-r[0]-i[0],a[1]-r[1]-i[1],a[2]-r[2]-i[2]]))}function Flatness(t,e,i,a){let r=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],n=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return Math.max(abs2(cross(r,unit(n))),abs2(cross(n,unit(r))))/9}function corners(t,e){return[t,[t[0],t[1],e[2]],[t[0],e[1],t[2]],[t[0],e[1],e[2]],[e[0],t[1],t[2]],[e[0],t[1],e[2]],[e[0],e[1],t[2]],e]}function minbound(t){return[Math.min(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.min(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.min(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function maxbound(t){return[Math.max(t[0][0],t[1][0],t[2][0],t[3][0],t[4][0],t[5][0],t[6][0],t[7][0]),Math.max(t[0][1],t[1][1],t[2][1],t[3][1],t[4][1],t[5][1],t[6][1],t[7][1]),Math.max(t[0][2],t[1][2],t[2][2],t[3][2],t[4][2],t[5][2],t[6][2],t[7][2])]}function COBTarget(t,e){mat4.fromTranslation(T,[center.x,center.y,center.z]),mat4.invert(cjMatInv,T),mat4.multiply(t,e,cjMatInv),mat4.multiply(t,T,t)}function setUniforms(t,e){let i=e==pixelShader;gl.useProgram(e),gl.enableVertexAttribArray(positionAttribute),i&&gl.enableVertexAttribArray(widthAttribute);let a=!i&&Lights.length>0;if(a&&gl.enableVertexAttribArray(normalAttribute),gl.enableVertexAttribArray(materialAttribute),e.projViewMatUniform=gl.getUniformLocation(e,"projViewMat"),e.viewMatUniform=gl.getUniformLocation(e,"viewMat"),e.normMatUniform=gl.getUniformLocation(e,"normMat"),e!=colorShader&&e!=transparentShader||gl.enableVertexAttribArray(colorAttribute),a)for(let t=0;t<Lights.length;++t)Lights[t].setUniform(e,t);for(let i=0;i<t.materials.length;++i)t.materials[i].setUniform(e,i);gl.uniformMatrix4fv(e.projViewMatUniform,!1,projViewMat),gl.uniformMatrix4fv(e.viewMatUniform,!1,viewMat),gl.uniformMatrix3fv(e.normMatUniform,!1,normMat)}function handleMouseDown(t){zoomEnabled||enableZoom(),mouseDownOrTouchActive=!0,lastMouseX=t.clientX,lastMouseY=t.clientY}let pinchStart,touchStartTime,pinch=!1;function pinchDistance(t){return Math.hypot(t[0].pageX-t[1].pageX,t[0].pageY-t[1].pageY)}function handleTouchStart(t){t.preventDefault(),zoomEnabled||enableZoom();let e=t.targetTouches;swipe=rotate=pinch=!1,zooming||(1!=e.length||mouseDownOrTouchActive||(touchStartTime=(new Date).getTime(),touchId=e[0].identifier,lastMouseX=e[0].pageX,lastMouseY=e[0].pageY),2!=e.length||mouseDownOrTouchActive||(touchId=e[0].identifier,pinchStart=pinchDistance(e),pinch=!0))}function handleMouseUpOrTouchEnd(t){mouseDownOrTouchActive=!1}function rotateScene(t,e,i,a,r){if(t==i&&e==a)return;let[n,s]=arcball([t,-e],[i,-a]);mat4.fromRotation(T,2*r*ArcballFactor*n/Zoom,s),mat4.multiply(rotMat,T,rotMat)}function shiftScene(t,e,i,a){let r=1/Zoom;shift.x+=(i-t)*r*halfCanvasWidth,shift.y-=(a-e)*r*halfCanvasHeight}function panScene(t,e,i,a){orthographic?shiftScene(t,e,i,a):(center.x+=(i-t)*(viewParam.xmax-viewParam.xmin),center.y-=(a-e)*(viewParam.ymax-viewParam.ymin))}function updateViewMatrix(){COBTarget(viewMat,rotMat),mat4.translate(viewMat,viewMat,[center.x,center.y,0]),mat3.fromMat4(viewMat3,viewMat),mat3.invert(normMat,viewMat3),mat4.multiply(projViewMat,projMat,viewMat)}function capzoom(){let t=Math.sqrt(Number.MAX_VALUE),e=1/t;Zoom<=e&&(Zoom=e),Zoom>=t&&(Zoom=t),(zoomRemeshFactor*Zoom<lastZoom||Zoom>zoomRemeshFactor*lastZoom)&&(remesh=!0,lastZoom=Zoom)}function zoomImage(t){let e=zoomStep*halfCanvasHeight*t;const i=Math.log(.1*Number.MAX_VALUE)/Math.log(zoomFactor);Math.abs(e)<i&&(Zoom*=zoomFactor**e,capzoom())}function normMouse(t){let e=t[0],i=t[1],a=Math.hypot(e,i);return a>1&&(denom=1/a,e*=denom,i*=denom),[e,i,Math.sqrt(Math.max(1-i*i-e*e,0))]}function arcball(t,e){let i=normMouse(t),a=normMouse(e),r=dot(i,a);return[r>1?0:r<-1?pi:Math.acos(r),unit(cross(i,a))]}function zoomScene(t,e,i,a){zoomImage(e-a)}const DRAGMODE_ROTATE=1,DRAGMODE_SHIFT=2,DRAGMODE_ZOOM=3,DRAGMODE_PAN=4;function processDrag(t,e,i,a=1){let r;switch(i){case 1:r=rotateScene;break;case 2:r=shiftScene;break;case 3:r=zoomScene;break;case 4:r=panScene;break;default:r=(t,e,i,a)=>{}}r((lastMouseX-halfCanvasWidth)/halfCanvasWidth,(lastMouseY-halfCanvasHeight)/halfCanvasHeight,(t-halfCanvasWidth)/halfCanvasWidth,(e-halfCanvasHeight)/halfCanvasHeight,a),lastMouseX=t,lastMouseY=e,setProjection(),draw()}let zoomEnabled=0;function enableZoom(){zoomEnabled=1,canvas.addEventListener("wheel",handleMouseWheel,!1)}function disableZoom(){zoomEnabled=0,canvas.removeEventListener("wheel",handleMouseWheel,!1)}function handleKey(t){if(zoomEnabled||enableZoom(),embedded&&zoomEnabled&&27==t.keyCode)return void disableZoom();let e=[];switch(t.key){case"x":e=[1,0,0];break;case"y":e=[0,1,0];break;case"z":e=[0,0,1];break;case"h":home();break;case"m":++wireframe,3==wireframe&&(wireframe=0),2!=wireframe&&(embedded||deleteShaders(),initShaders()),remesh=!0,draw();break;case"+":case"=":case">":expand();break;case"-":case"_":case"<":shrink()}e.length>0&&(mat4.rotate(rotMat,rotMat,.1,e),updateViewMatrix(),draw())}function setZoom(){capzoom(),setProjection(),draw()}function handleMouseWheel(t){t.preventDefault(),t.deltaY<0?Zoom*=zoomFactor:Zoom/=zoomFactor,setZoom()}function handleMouseMove(t){if(!mouseDownOrTouchActive)return;let e,i=t.clientX,a=t.clientY;e=t.getModifierState("Control")?2:t.getModifierState("Shift")?3:t.getModifierState("Alt")?4:1,processDrag(i,a,e)}let zooming=!1,swipe=!1,rotate=!1;function handleTouchMove(t){if(t.preventDefault(),zooming)return;let e=t.targetTouches;if(!pinch&&1==e.length&&touchId==e[0].identifier){let t=e[0].pageX,i=e[0].pageY,a=t-lastMouseX,r=i-lastMouseY,n=a*a+r*r<=shiftHoldDistance*shiftHoldDistance;if(n&&!swipe&&!rotate&&(new Date).getTime()-touchStartTime>shiftWaitTime&&(navigator.vibrate&&window.navigator.vibrate(vibrateTime),swipe=!0),swipe)processDrag(t,i,2);else if(!n){rotate=!0,processDrag(e[0].pageX,e[0].pageY,1,.5)}}if(pinch&&!swipe&&2==e.length&&touchId==e[0].identifier){let t=pinchDistance(e),i=t-pinchStart;zooming=!0,i*=zoomPinchFactor,i>zoomPinchCap&&(i=zoomPinchCap),i<-zoomPinchCap&&(i=-zoomPinchCap),zoomImage(i/size2),pinchStart=t,swipe=rotate=zooming=!1,setProjection(),draw()}}let pixelShader,materialShader,colorShader,transparentShader,zbuffer=[];function transformVertices(t){let e=viewMat[2],i=viewMat[6],a=viewMat[10];zbuffer.length=t.length;for(let r=0;r<t.length;++r){let n=6*r;zbuffer[r]=e*t[n]+i*t[n+1]+a*t[n+2]}}function drawMaterial0(){drawBuffer(material0Data,pixelShader),material0Data.clear()}function drawMaterial1(){drawBuffer(material1Data,materialShader),material1Data.clear()}function drawMaterial(){drawBuffer(materialData,materialShader),materialData.clear()}function drawColor(){drawBuffer(colorData,colorShader),colorData.clear()}function drawTriangle(){drawBuffer(triangleData,transparentShader),triangleData.rendered=!1,triangleData.clear()}function drawTransparent(){let t=transparentData.indices;if(wireframe>0)return drawBuffer(transparentData,transparentShader,t),void transparentData.clear();if(t.length>0){transformVertices(transparentData.vertices);let e=t.length/3,i=Array(e).fill().map((t,e)=>e);i.sort((function(e,i){let a=3*e;Ia=t[a],Ib=t[a+1],Ic=t[a+2];let r=3*i;return IA=t[r],IB=t[r+1],IC=t[r+2],zbuffer[Ia]+zbuffer[Ib]+zbuffer[Ic]<zbuffer[IA]+zbuffer[IB]+zbuffer[IC]?-1:1}));let a=Array(t.length);for(let r=0;r<e;++r){let e=3*i[r];a[3*r]=t[e],a[3*r+1]=t[e+1],a[3*r+2]=t[e+2]}gl.depthMask(!1),drawBuffer(transparentData,transparentShader,a),transparentData.rendered=!1,gl.depthMask(!0)}transparentData.clear()}function drawBuffers(){drawMaterial0(),drawMaterial1(),drawMaterial(),drawColor(),drawTriangle(),drawTransparent()}function draw(){embedded&&(offscreen.width=canvasWidth,offscreen.height=canvasHeight,setViewport()),gl.clearColor(Background[0],Background[1],Background[2],Background[3]),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);for(let t=0;t<P.length;++t)P[t].render();drawBuffers(),embedded&&(context.clearRect(0,0,canvasWidth,canvasHeight),context.drawImage(offscreen,0,0)),0==wireframe&&(remesh=!1)}function setDimensions(t,e,i,a){let r=t/e,n=1/Zoom,s=(i/t+viewportshift[0])*Zoom,o=(a/e+viewportshift[1])*Zoom;if(orthographic){let t=B[0]-b[0],e=B[1]-b[1];if(t<e*r){let t=.5*e*r*n,i=2*t*s,a=e*n*o;viewParam.xmin=-t-i,viewParam.xmax=t-i,viewParam.ymin=b[1]*n-a,viewParam.ymax=B[1]*n-a}else{let e=.5*t/(r*Zoom),i=t*n*s,a=2*e*o;viewParam.xmin=b[0]*n-i,viewParam.xmax=B[0]*n-i,viewParam.ymin=-e-a,viewParam.ymax=e-a}}else{let t=H*n,e=t*r,i=2*e*s,a=2*t*o;viewParam.xmin=-e-i,viewParam.xmax=e-i,viewParam.ymin=-t-a,viewParam.ymax=t-a}}function setProjection(){setDimensions(canvasWidth,canvasHeight,shift.x,shift.y),(orthographic?mat4.ortho:mat4.frustum)(projMat,viewParam.xmin,viewParam.xmax,viewParam.ymin,viewParam.ymax,-viewParam.zmax,-viewParam.zmin),updateViewMatrix()}function initProjection(){H=-Math.tan(.5*angle)*B[2],center.x=center.y=0,center.z=.5*(b[2]+B[2]),lastZoom=Zoom=zoom0,viewParam.zmin=b[2],viewParam.zmax=B[2],shift.x=shift.y=0}function setViewport(){gl.viewportWidth=canvasWidth,gl.viewportHeight=canvasHeight,gl.viewport(.5*(canvas.width-canvasWidth),.5*(canvas.height-canvasHeight),canvasWidth,canvasHeight),gl.scissor(0,0,canvas.width,canvas.height)}function setCanvas(){embedded&&(canvas.width=offscreen.width=canvasWidth,canvas.height=offscreen.height=canvasHeight),size2=Math.hypot(canvasWidth,canvasHeight),halfCanvasWidth=.5*canvas.width,halfCanvasHeight=.5*canvas.height,ArcballFactor=1+8*Math.hypot(viewportmargin[0],viewportmargin[1])/size2}function setsize(t,e){t>maxViewportWidth&&(t=maxViewportWidth),e>maxViewportHeight&&(e=maxViewportHeight),shift.x*=t/canvasWidth,shift.y*=e/canvasHeight,canvasWidth=t,canvasHeight=e,setCanvas(),setViewport(),setProjection(),remesh=!0}function resize(){if(zoom0=Zoom0,absolute&&!embedded)canvasWidth=canvasWidth0*window.devicePixelRatio,canvasHeight=canvasHeight0*window.devicePixelRatio;else{let t=canvasWidth0/canvasHeight0;canvasWidth=Math.max(window.innerWidth-10,10),canvasHeight=Math.max(window.innerHeight-10,10),!orthographic&&canvasWidth<canvasHeight*t&&(zoom0*=canvasWidth/(canvasHeight*t))}canvas.width=canvasWidth,canvas.height=canvasHeight;window.innerWidth,window.innerHeight;viewportshift[0]/=zoom0,viewportshift[1]/=zoom0,setsize(canvasWidth,canvasHeight),redraw()}function expand(){Zoom*=zoomFactor,setZoom()}function shrink(){Zoom/=zoomFactor,setZoom()}class Align{constructor(t,e){if(this.center=t,e){let t=e[0],i=e[1];this.ct=Math.cos(t),this.st=Math.sin(t),this.cp=Math.cos(i),this.sp=Math.sin(i)}}T0(t){return[t[0]+this.center[0],t[1]+this.center[1],t[2]+this.center[2]]}T(t){let e=t[0],i=t[1],a=t[2],r=e*this.ct+a*this.st;return[r*this.cp-i*this.sp+this.center[0],r*this.sp+i*this.cp+this.center[1],-e*this.st+a*this.ct+this.center[2]]}}function Tcorners(t,e,i){let a=[t(e),t([e[0],e[1],i[2]]),t([e[0],i[1],e[2]]),t([e[0],i[1],i[2]]),t([i[0],e[1],e[2]]),t([i[0],e[1],i[2]]),t([i[0],i[1],e[2]]),t(i)];return[minbound(a),maxbound(a)]}function sphere(t,e,i,r,n){let s,o,h,l,c,d,m=.524670512339254,f=.595936986722291,u=.954967051233925,p=.0820155480083437,v=.996685028842544,g=.0549670512339254,x=.998880711874577,w=.0405017186586849,M=[[[1,0,0],[1,0,m],[f,0,u],[p,0,v],[1,a,0],[1,a,m],[f,a*f,u],[p,a*p,v],[a,1,0],[a,1,m],[a*f,f,u],[a*p,p,v],[0,1,0],[0,1,m],[0,f,u],[0,p,v]],[[p,0,v],[p,a*p,v],[g,0,x],[a*p,p,v],[w,w,1],[.05*a,0,1],[0,p,v],[0,g,x],[0,.05*a,1],[0,0,1]]],b=new Align(t,n);function S(t){let e=Array(t.length);for(let i=0;i<t.length;++i){let a=t[i];e[i]=c([s*a[0],o*a[1],h*a[2]])}return e}n?(l=1,d=0,c=b.T.bind(b)):(l=-1,d=-e,c=b.T0.bind(b));let A=Tcorners(c,[-e,-e,d],[e,e,e]),y=A[0],T=A[1];for(let t=-1;t<=1;t+=2){s=t*e;for(let t=-1;t<=1;t+=2){o=t*e;for(let t=l;t<=1;t+=2){h=t*e;for(let t=0;t<2;++t)P.push(new BezierPatch(S(M[t]),i,r,y,T))}}}}let a=4/3*(Math.sqrt(2)-1);function disk(t,e,i,r,n){let s=1-2*a/3,o=[[1,0,0],[1,-a,0],[a,-1,0],[0,-1,0],[1,a,0],[s,0,0],[0,-s,0],[-a,-1,0],[a,1,0],[0,s,0],[-s,0,0],[-1,-a,0],[0,1,0],[-a,1,0],[-1,a,0],[-1,0,0]],h=new Align(t,n);let l=Tcorners(h.T.bind(h),[-e,-e,0],[e,e,0]);P.push(new BezierPatch(function(t){let i=Array(t.length);for(let a=0;a<t.length;++a){let r=t[a];i[a]=h.T([e*r[0],e*r[1],0])}return i}(o),i,r,l[0],l[1]))}function cylinder(t,e,i,r,n,s,o){let h,l,c=[[1,0,0],[1,0,1/3],[1,0,2/3],[1,0,1],[1,a,0],[1,a,1/3],[1,a,2/3],[1,a,1],[a,1,0],[a,1,1/3],[a,1,2/3],[a,1,1],[0,1,0],[0,1,1/3],[0,1,2/3],[0,1,1]],d=new Align(t,s);function m(t){let e=Array(t.length);for(let a=0;a<t.length;++a){let r=t[a];e[a]=d.T([h*r[0],l*r[1],i*r[2]])}return e}let f=Tcorners(d.T.bind(d),[-e,-e,0],[e,e,i]),u=f[0],p=f[1];for(let t=-1;t<=1;t+=2){h=t*e;for(let t=-1;t<=1;t+=2)l=t*e,P.push(new BezierPatch(m(c),r,n,u,p))}if(o){let e=d.T([0,0,i]);P.push(new BezierCurve([t,e],r,n,t,e))}}function rmf(t,e,i,a,r){class n{constructor(t,e,i){this.p=t,this.r=e,this.t=i,this.s=cross(i,e)}}let s=Number.EPSILON*Math.max(abs2(t),abs2(e),abs2(i),abs2(a));function o(r){if(1==r){let r=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return abs2(r)>s?unit(r):(r=[2*i[0]-e[0]-a[0],2*i[1]-e[1]-a[1],2*i[2]-e[2]-a[2]],abs2(r)>s?unit(r):[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])])}let n=[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])],o=[2*(t[0]+i[0])-4*e[0],2*(t[1]+i[1])-4*e[1],2*(t[2]+i[2])-4*e[2]],h=[e[0]-t[0],e[1]-t[1],e[2]-t[2]],l=r*r,c=[n[0]*l+o[0]*r+h[0],n[1]*l+o[1]*r+h[1],n[2]*l+o[2]*r+h[2]];return abs2(c)>s?unit(c):(l=2*r,c=[n[0]*l+o[0],n[1]*l+o[1],n[2]*l+o[2]],abs2(c)>s?unit(c):unit(n))}let h=Array(r.length),l=[e[0]-t[0],e[1]-t[1],e[2]-t[2]];abs2(l)<s&&(l=[t[0]-2*e[0]+i[0],t[1]-2*e[1]+i[1],t[2]-2*e[2]+i[2]],abs2(l)<s&&(l=[a[0]-t[0]+3*(e[0]-i[0]),a[1]-t[1]+3*(e[1]-i[1]),a[2]-t[2]+3*(e[2]-i[2])])),l=unit(l);let c=function(t){let e=cross(t,[0,1,0]),i=Number.EPSILON*abs2(t);return abs2(e)>i?unit(e):(e=cross(t,[0,0,1]),abs2(e)>i?unit(e):[1,0,0])}(l);h[0]=new n(t,c,l);for(let s=1;s<r.length;++s){let l=h[s-1],c=r[s],d=1-c,m=d*d,f=m*d,u=3*c;m*=u,d*=u*c;let p=c*c*c,v=[f*t[0]+m*e[0]+d*i[0]+p*a[0],f*t[1]+m*e[1]+d*i[1]+p*a[1],f*t[2]+m*e[2]+d*i[2]+p*a[2]],g=[v[0]-l.p[0],v[1]-l.p[1],v[2]-l.p[2]];if(0!=g[0]||0!=g[1]||0!=g[2]){let t=l.r,e=unit(g),i=l.t,a=dot(e,i),r=[i[0]-2*a*e[0],i[1]-2*a*e[1],i[2]-2*a*e[2]];i=o(c);let d=2*dot(e,t),m=[t[0]-d*e[0],t[1]-d*e[1],t[2]-d*e[2]],f=unit([i[0]-r[0],i[1]-r[1],i[2]-r[2]]),u=2*dot(f,m);m=[m[0]-u*f[0],m[1]-u*f[1],m[2]-u*f[2]],h[s]=new n(v,unit(m),unit(i))}else h[s]=h[s-1]}return h}function tube(t,e,i,r,n,s,o){let h=rmf(t[0],t[1],t[2],t[3],[0,1/3,2/3,1]),l=a*e,c=[[e,0],[e,l],[l,e],[0,e]];function d(e,a,o,l){let d=Array(16);for(let i=0;i<4;++i){let r=h[i],n=r.r[0],s=r.s[0],m=n*e+s*a,f=n*o+s*l;n=r.r[1],s=r.s[1];let u=n*e+s*a,p=n*o+s*l;n=r.r[2],s=r.s[2];let v=n*e+s*a,g=n*o+s*l,x=t[i],w=x[0];w1=x[1],w2=x[2];for(let t=0;t<4;++t){let e=c[t],a=e[0],r=e[1];d[4*i+t]=[m*a+f*r+w,u*a+p*r+w1,v*a+g*r+w2]}}P.push(new BezierPatch(d,i,r,n,s))}d(1,0,0,1),d(0,-1,1,0),d(-1,0,0,-1),d(0,1,-1,0),o&&P.push(new BezierCurve(t,i,r,n,s))}function webGLStart(){canvas=document.getElementById("Asymptote"),embedded=window.top.document!=document,initGL(),gl.enable(gl.BLEND),gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA),gl.enable(gl.DEPTH_TEST),gl.enable(gl.SCISSOR_TEST),canvas.onmousedown=handleMouseDown,document.onmouseup=handleMouseUpOrTouchEnd,document.onmousemove=handleMouseMove,canvas.onkeydown=handleKey,embedded||enableZoom(),canvas.addEventListener("touchstart",handleTouchStart,!1),canvas.addEventListener("touchend",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchcancel",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchleave",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchmove",handleTouchMove,!1),document.addEventListener("keydown",handleKey,!1),canvasWidth0=canvasWidth,canvasHeight0=canvasHeight,mat4.identity(rotMat),0!=window.innerWidth&&0!=window.innerHeight&&resize(),window.addEventListener("resize",resize,!1)}
+let vertex="\n#ifdef WEBGL2\n#define IN in\n#define OUT out\n#else\n#define IN attribute\n#define OUT varying\n#endif\n\nIN vec3 position;\n#ifdef WIDTH\nIN float width;\n#endif\n#ifdef NORMAL\nIN vec3 normal;\n#endif\n\nIN float materialIndex;\n\n#ifdef WEBGL2\nflat out int MaterialIndex;\n#ifdef COLOR\nOUT vec4 Color;\n#endif\n\n#else\nOUT vec4 diffuse;\nOUT vec3 specular;\nOUT float roughness,metallic,fresnel0;\nOUT vec4 emissive;\n\nstruct Material {\n vec4 diffuse,emissive,specular;\n vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n#endif\n\n#ifdef COLOR\nIN vec4 color;\n#endif\n\nuniform mat3 normMat;\nuniform mat4 viewMat;\nuniform mat4 projViewMat;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\nOUT vec3 ViewPosition;\n#endif\nOUT vec3 Normal;\n#endif\n\nvoid main(void)\n{\n vec4 v=vec4(position,1.0);\n gl_Position=projViewMat*v;\n\n#ifdef NORMAL\n#ifndef ORTHOGRAPHIC\n ViewPosition=(viewMat*v).xyz;\n#endif\n Normal=normalize(normal*normMat);\n#endif\n\n#ifdef WEBGL2\n MaterialIndex=int(materialIndex);\n#ifdef COLOR\n Color=color;\n#endif\n#else\n#ifdef NORMAL\n Material m;\n#ifdef TRANSPARENT\n m=Materials[int(abs(materialIndex))-1];\n emissive=m.emissive;\n if(materialIndex >= 0.0)\n diffuse=m.diffuse;\n else {\n diffuse=color;\n#if nlights == 0\n emissive += color;\n#endif\n }\n#else\n m=Materials[int(materialIndex)];\n emissive=m.emissive;\n#ifdef COLOR\n diffuse=color;\n#if nlights == 0\n emissive += color;\n#endif\n#else\n diffuse=m.diffuse;\n#endif // COLOR\n#endif // TRANSPARENT\n specular=m.specular.rgb;\n vec4 parameters=m.parameters;\n roughness=1.0-parameters[0];\n metallic=parameters[1];\n fresnel0=parameters[2];\n#else\n emissive=Materials[int(materialIndex)].emissive;\n#endif // NORMAL\n#endif // WEBGL2\n\n#ifdef WIDTH\n gl_PointSize=width;\n#endif\n}\n",fragment="\n#ifdef WEBGL2\n#define IN in\nout vec4 outValue;\n#define OUTVALUE outValue\n#else\n#define IN varying\n#define OUTVALUE gl_FragColor\n#endif\n\n#ifdef WEBGL2\nflat in int MaterialIndex;\n\nstruct Material {\n vec4 diffuse,emissive,specular;\n vec4 parameters;\n};\n\nuniform Material Materials[Nmaterials];\n\nvec4 diffuse;\nvec3 specular;\nfloat roughness,metallic,fresnel0;\nvec4 emissive;\n\n#ifdef COLOR\nin vec4 Color;\n#endif\n\n#else\nIN vec4 diffuse;\nIN vec3 specular;\nIN float roughness,metallic,fresnel0;\nIN vec4 emissive;\n#endif\n\n#ifdef NORMAL\n\n#ifndef ORTHOGRAPHIC\nIN vec3 ViewPosition;\n#endif\nIN vec3 Normal;\n\nvec3 normal;\n\nstruct Light {\n vec3 direction;\n vec3 color;\n};\n\nuniform Light Lights[Nlights];\n\n#ifdef USE_IBL\nuniform sampler2D reflBRDFSampler;\nuniform sampler2D diffuseSampler;\nuniform sampler2D reflImgSampler;\n\nconst float pi=acos(-1.0);\nconst float piInv=1.0/pi;\nconst float twopi=2.0*pi;\nconst float twopiInv=1.0/twopi;\n\n// (x,y,z) -> (r,theta,phi);\n// theta -> [0,pi]: colatitude\n// phi -> [-pi,pi]: longitude\nvec3 cart2sphere(vec3 cart)\n{\n float x=cart.x;\n float y=cart.z;\n float z=cart.y;\n\n float r=length(cart);\n float theta=r > 0.0 ? acos(z/r) : 0.0;\n float phi=atan(y,x);\n\n return vec3(r,theta,phi);\n}\n\nvec2 normalizedAngle(vec3 cartVec)\n{\n vec3 sphericalVec=cart2sphere(cartVec);\n sphericalVec.y=sphericalVec.y*piInv;\n sphericalVec.z=0.75-sphericalVec.z*twopiInv;\n return sphericalVec.zy;\n}\n\nvec3 IBLColor(vec3 viewDir)\n{\n vec3 IBLDiffuse=diffuse.rgb*texture(diffuseSampler,normalizedAngle(normal)).rgb;\n vec3 reflectVec=normalize(reflect(-viewDir,normal));\n vec2 reflCoord=normalizedAngle(reflectVec);\n vec3 IBLRefl=textureLod(reflImgSampler,reflCoord,roughness*ROUGHNESS_STEP_COUNT).rgb;\n vec2 IBLbrdf=texture(reflBRDFSampler,vec2(dot(normal,viewDir),roughness)).rg;\n float specularMultiplier=fresnel0*IBLbrdf.x+IBLbrdf.y;\n vec3 dielectric=IBLDiffuse+specularMultiplier*IBLRefl;\n vec3 metal=diffuse.rgb*IBLRefl;\n return mix(dielectric,metal,metallic);\n}\n#else\nfloat Roughness2;\nfloat NDF_TRG(vec3 h)\n{\n float ndoth=max(dot(normal,h),0.0);\n float alpha2=Roughness2*Roughness2;\n float denom=ndoth*ndoth*(alpha2-1.0)+1.0;\n return denom != 0.0 ? alpha2/(denom*denom) : 0.0;\n}\n\nfloat GGX_Geom(vec3 v)\n{\n float ndotv=max(dot(v,normal),0.0);\n float ap=1.0+Roughness2;\n float k=0.125*ap*ap;\n return ndotv/((ndotv*(1.0-k))+k);\n}\n\nfloat Geom(vec3 v, vec3 l)\n{\n return GGX_Geom(v)*GGX_Geom(l);\n}\n\nfloat Fresnel(vec3 h, vec3 v, float fresnel0)\n{\n float a=1.0-max(dot(h,v),0.0);\n float b=a*a;\n return fresnel0+(1.0-fresnel0)*b*b*a;\n}\n\n// physical based shading using UE4 model.\nvec3 BRDF(vec3 viewDirection, vec3 lightDirection)\n{\n vec3 lambertian=diffuse.rgb;\n vec3 h=normalize(lightDirection+viewDirection);\n\n float omegain=max(dot(viewDirection,normal),0.0);\n float omegaln=max(dot(lightDirection,normal),0.0);\n\n float D=NDF_TRG(h);\n float G=Geom(viewDirection,lightDirection);\n float F=Fresnel(h,viewDirection,fresnel0);\n\n float denom=4.0*omegain*omegaln;\n float rawReflectance=denom > 0.0 ? (D*G)/denom : 0.0;\n\n vec3 dielectric=mix(lambertian,rawReflectance*specular,F);\n vec3 metal=rawReflectance*diffuse.rgb;\n\n return mix(dielectric,metal,metallic);\n}\n#endif\n\n#endif\n\nvoid main(void)\n{\n#ifdef WEBGL2\n#ifdef NORMAL\n Material m;\n#ifdef TRANSPARENT\n m=Materials[abs(MaterialIndex)-1];\n emissive=m.emissive;\n if(MaterialIndex >= 0)\n diffuse=m.diffuse;\n else {\n diffuse=Color;\n#if nlights == 0\n emissive += Color;\n#endif\n }\n#else\n m=Materials[MaterialIndex];\n emissive=m.emissive;\n#ifdef COLOR\n diffuse=Color;\n#if nlights == 0\n emissive += Color;\n#endif\n#else\n diffuse=m.diffuse;\n#endif // COLOR\n#endif // TRANSPARENT\n specular=m.specular.rgb;\n vec4 parameters=m.parameters;\n roughness=1.0-parameters[0];\n metallic=parameters[1];\n fresnel0=parameters[2];\n#else\n emissive=Materials[MaterialIndex].emissive;\n#endif // NORMAL\n#endif // WEBGL2\n\n#if defined(NORMAL) && nlights > 0\n normal=normalize(Normal);\n normal=gl_FrontFacing ? normal : -normal;\n#ifdef ORTHOGRAPHIC\n vec3 viewDir=vec3(0.0,0.0,1.0);\n#else\n vec3 viewDir=-normalize(ViewPosition);\n#endif\n\nvec3 color;\n#ifdef USE_IBL\n color=IBLColor(viewDir);\n#else\n Roughness2=roughness*roughness;\n color=emissive.rgb;\n for(int i=0; i < nlights; ++i) {\n Light Li=Lights[i];\n vec3 L=Li.direction;\n float cosTheta=max(dot(normal,L),0.0);\n vec3 radiance=cosTheta*Li.color;\n color += BRDF(viewDir,L)*radiance;\n }\n#endif\n OUTVALUE=vec4(color,diffuse.a);\n#else\n OUTVALUE=emissive;\n#endif\n}\n";!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var a in i)("object"==typeof exports?exports:e)[a]=i[a]}}("undefined"!=typeof self?self:this,(function(){return function(e){var t={};function i(a){if(t[a])return t[a].exports;var n=t[a]={i:a,l:!1,exports:{}};return e[a].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=e,i.c=t,i.d=function(e,t,a){i.o(e,t)||Object.defineProperty(e,t,{configurable:!1,enumerable:!0,get:a})},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="",i(i.s=1)}([function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setMatrixArrayType=function(e){t.ARRAY_TYPE=e},t.toRadian=function(e){return e*n},t.equals=function(e,t){return Math.abs(e-t)<=a*Math.max(1,Math.abs(e),Math.abs(t))};var a=t.EPSILON=1e-6;t.ARRAY_TYPE="undefined"!=typeof Float32Array?Float32Array:Array,t.RANDOM=Math.random;var n=Math.PI/180},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.mat4=t.mat3=void 0;var a=r(i(2)),n=r(i(3));function r(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}t.mat3=a,t.mat4=n},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.create=function(){var e=new a.ARRAY_TYPE(9);return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=1,e[5]=0,e[6]=0,e[7]=0,e[8]=1,e},t.fromMat4=function(e,t){return e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[4],e[4]=t[5],e[5]=t[6],e[6]=t[8],e[7]=t[9],e[8]=t[10],e},t.invert=function(e,t){var i=t[0],a=t[1],n=t[2],r=t[3],s=t[4],o=t[5],l=t[6],h=t[7],c=t[8],d=c*s-o*h,m=-c*r+o*l,f=h*r-s*l,u=i*d+a*m+n*f;if(!u)return null;return u=1/u,e[0]=d*u,e[1]=(-c*a+n*h)*u,e[2]=(o*a-n*s)*u,e[3]=m*u,e[4]=(c*i-n*l)*u,e[5]=(-o*i+n*r)*u,e[6]=f*u,e[7]=(-h*i+a*l)*u,e[8]=(s*i-a*r)*u,e};var a=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}(i(0))},function(e,t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.create=function(){var e=new a.ARRAY_TYPE(16);return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},t.identity=function(e){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},t.invert=function(e,t){var i=t[0],a=t[1],n=t[2],r=t[3],s=t[4],o=t[5],l=t[6],h=t[7],c=t[8],d=t[9],m=t[10],f=t[11],u=t[12],p=t[13],g=t[14],v=t[15],x=i*o-a*s,w=i*l-n*s,M=i*h-r*s,b=a*l-n*o,T=a*h-r*o,S=n*h-r*l,R=c*p-d*u,I=c*g-m*u,A=c*v-f*u,E=d*g-m*p,P=d*v-f*p,L=m*v-f*g,D=x*L-w*P+M*E+b*A-T*I+S*R;if(!D)return null;return D=1/D,e[0]=(o*L-l*P+h*E)*D,e[1]=(n*P-a*L-r*E)*D,e[2]=(p*S-g*T+v*b)*D,e[3]=(m*T-d*S-f*b)*D,e[4]=(l*A-s*L-h*I)*D,e[5]=(i*L-n*A+r*I)*D,e[6]=(g*M-u*S-v*w)*D,e[7]=(c*S-m*M+f*w)*D,e[8]=(s*P-o*A+h*R)*D,e[9]=(a*A-i*P-r*R)*D,e[10]=(u*T-p*M+v*x)*D,e[11]=(d*M-c*T-f*x)*D,e[12]=(o*I-s*E-l*R)*D,e[13]=(i*E-a*I+n*R)*D,e[14]=(p*w-u*b-g*x)*D,e[15]=(c*b-d*w+m*x)*D,e},t.multiply=n,t.translate=function(e,t,i){var a=i[0],n=i[1],r=i[2],s=void 0,o=void 0,l=void 0,h=void 0,c=void 0,d=void 0,m=void 0,f=void 0,u=void 0,p=void 0,g=void 0,v=void 0;t===e?(e[12]=t[0]*a+t[4]*n+t[8]*r+t[12],e[13]=t[1]*a+t[5]*n+t[9]*r+t[13],e[14]=t[2]*a+t[6]*n+t[10]*r+t[14],e[15]=t[3]*a+t[7]*n+t[11]*r+t[15]):(s=t[0],o=t[1],l=t[2],h=t[3],c=t[4],d=t[5],m=t[6],f=t[7],u=t[8],p=t[9],g=t[10],v=t[11],e[0]=s,e[1]=o,e[2]=l,e[3]=h,e[4]=c,e[5]=d,e[6]=m,e[7]=f,e[8]=u,e[9]=p,e[10]=g,e[11]=v,e[12]=s*a+c*n+u*r+t[12],e[13]=o*a+d*n+p*r+t[13],e[14]=l*a+m*n+g*r+t[14],e[15]=h*a+f*n+v*r+t[15]);return e},t.rotate=function(e,t,i,n){var r,s,o,l,h,c,d,m,f,u,p,g,v,x,w,M,b,T,S,R,I,A,E,P,L=n[0],D=n[1],y=n[2],O=Math.sqrt(L*L+D*D+y*y);if(Math.abs(O)<a.EPSILON)return null;L*=O=1/O,D*=O,y*=O,r=Math.sin(i),s=Math.cos(i),o=1-s,l=t[0],h=t[1],c=t[2],d=t[3],m=t[4],f=t[5],u=t[6],p=t[7],g=t[8],v=t[9],x=t[10],w=t[11],M=L*L*o+s,b=D*L*o+y*r,T=y*L*o-D*r,S=L*D*o-y*r,R=D*D*o+s,I=y*D*o+L*r,A=L*y*o+D*r,E=D*y*o-L*r,P=y*y*o+s,e[0]=l*M+m*b+g*T,e[1]=h*M+f*b+v*T,e[2]=c*M+u*b+x*T,e[3]=d*M+p*b+w*T,e[4]=l*S+m*R+g*I,e[5]=h*S+f*R+v*I,e[6]=c*S+u*R+x*I,e[7]=d*S+p*R+w*I,e[8]=l*A+m*E+g*P,e[9]=h*A+f*E+v*P,e[10]=c*A+u*E+x*P,e[11]=d*A+p*E+w*P,t!==e&&(e[12]=t[12],e[13]=t[13],e[14]=t[14],e[15]=t[15]);return e},t.fromTranslation=function(e,t){return e[0]=1,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=1,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=1,e[11]=0,e[12]=t[0],e[13]=t[1],e[14]=t[2],e[15]=1,e},t.fromRotation=function(e,t,i){var n,r,s,o=i[0],l=i[1],h=i[2],c=Math.sqrt(o*o+l*l+h*h);if(Math.abs(c)<a.EPSILON)return null;return o*=c=1/c,l*=c,h*=c,n=Math.sin(t),r=Math.cos(t),s=1-r,e[0]=o*o*s+r,e[1]=l*o*s+h*n,e[2]=h*o*s-l*n,e[3]=0,e[4]=o*l*s-h*n,e[5]=l*l*s+r,e[6]=h*l*s+o*n,e[7]=0,e[8]=o*h*s+l*n,e[9]=l*h*s-o*n,e[10]=h*h*s+r,e[11]=0,e[12]=0,e[13]=0,e[14]=0,e[15]=1,e},t.frustum=function(e,t,i,a,n,r,s){var o=1/(i-t),l=1/(n-a),h=1/(r-s);return e[0]=2*r*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=2*r*l,e[6]=0,e[7]=0,e[8]=(i+t)*o,e[9]=(n+a)*l,e[10]=(s+r)*h,e[11]=-1,e[12]=0,e[13]=0,e[14]=s*r*2*h,e[15]=0,e},t.ortho=function(e,t,i,a,n,r,s){var o=1/(t-i),l=1/(a-n),h=1/(r-s);return e[0]=-2*o,e[1]=0,e[2]=0,e[3]=0,e[4]=0,e[5]=-2*l,e[6]=0,e[7]=0,e[8]=0,e[9]=0,e[10]=2*h,e[11]=0,e[12]=(t+i)*o,e[13]=(n+a)*l,e[14]=(s+r)*h,e[15]=1,e};var a=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t[i]=e[i]);return t.default=e,t}(i(0));function n(e,t,i){var a=t[0],n=t[1],r=t[2],s=t[3],o=t[4],l=t[5],h=t[6],c=t[7],d=t[8],m=t[9],f=t[10],u=t[11],p=t[12],g=t[13],v=t[14],x=t[15],w=i[0],M=i[1],b=i[2],T=i[3];return e[0]=w*a+M*o+b*d+T*p,e[1]=w*n+M*l+b*m+T*g,e[2]=w*r+M*h+b*f+T*v,e[3]=w*s+M*c+b*u+T*x,w=i[4],M=i[5],b=i[6],T=i[7],e[4]=w*a+M*o+b*d+T*p,e[5]=w*n+M*l+b*m+T*g,e[6]=w*r+M*h+b*f+T*v,e[7]=w*s+M*c+b*u+T*x,w=i[8],M=i[9],b=i[10],T=i[11],e[8]=w*a+M*o+b*d+T*p,e[9]=w*n+M*l+b*m+T*g,e[10]=w*r+M*h+b*f+T*v,e[11]=w*s+M*c+b*u+T*x,w=i[12],M=i[13],b=i[14],T=i[15],e[12]=w*a+M*o+b*d+T*p,e[13]=w*n+M*l+b*m+T*g,e[14]=w*r+M*h+b*f+T*v,e[15]=w*s+M*c+b*u+T*x,e}}])}));let canvasWidth,canvasHeight,imageURL,image,minBound,maxBound,orthographic,angleOfView,initialZoom,viewportMargin,zoomFactor,zoomPinchFactor,zoomPinchCap,zoomStep,shiftHoldDistance,shiftWaitTime,vibrateTime,canvasWidth0,canvasHeight0,zoom0,embedded,canvas,gl,alpha,offscreen2,context,maxMaterials,halfCanvasWidth,halfCanvasHeight,P=[],Materials=[],Lights=[],Centers=[],Background=[1,1,1,1],absolute=!1,ibl=!1,viewportShift=[0,0],webgl2=!1,nlights=0,Nmaterials=2,materials=[];const pixelResolution=.75,zoomRemeshFactor=1.5,FillFactor=.1,windowTrim=10,third=1/3;let Zoom,lastZoom,maxViewportWidth,maxViewportHeight,H,zmin,zmax,size2,ArcballFactor,rotMat=mat4.create(),projMat=mat4.create(),viewMat=mat4.create(),projViewMat=mat4.create(),normMat=mat3.create(),viewMat3=mat3.create(),cjMatInv=mat4.create(),T=mat4.create(),center={x:0,y:0,z:0},shift={x:0,y:0},viewParam={xmin:0,xmax:0,ymin:0,ymax:0,zmin:0,zmax:0},remesh=!0,wireframe=0,mouseDownOrTouchActive=!1,lastMouseX=null,lastMouseY=null,touchID=null,Positions=[],Normals=[],Colors=[],Indices=[],IBLReflMap=null,IBLDiffuseMap=null,IBLbdrfMap=null;function IBLReady(){return null!==IBLReflMap&&null!==IBLDiffuseMap&&null!==IBLbdrfMap}function SetIBL(){embedded||deleteShaders(),initShaders(ibl)}let roughnessStepCount=8;class Material{constructor(e,t,i,a,n,r){this.diffuse=e,this.emissive=t,this.specular=i,this.shininess=a,this.metallic=n,this.fresnel0=r}setUniform(e,t){let i=i=>gl.getUniformLocation(e,"Materials["+t+"]."+i);gl.uniform4fv(i("diffuse"),new Float32Array(this.diffuse)),gl.uniform4fv(i("emissive"),new Float32Array(this.emissive)),gl.uniform4fv(i("specular"),new Float32Array(this.specular)),gl.uniform4f(i("parameters"),this.shininess,this.metallic,this.fresnel0,0)}}let indexExt,TRIANGLES,material0Data,material1Data,materialData,colorData,transparentData,triangleData,materialIndex,enumPointLight=1,enumDirectionalLight=2;class Light{constructor(e,t){this.direction=e,this.color=t}setUniform(e,t){let i=i=>gl.getUniformLocation(e,"Lights["+t+"]."+i);gl.uniform3fv(i("direction"),new Float32Array(this.direction)),gl.uniform3fv(i("color"),new Float32Array(this.color))}}function initShaders(e=!1){let t=gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS);maxMaterials=Math.floor((t-14)/4),Nmaterials=Math.min(Math.max(Nmaterials,Materials.length),maxMaterials),pixelOpt=["WIDTH"],materialOpt=["NORMAL"],colorOpt=["NORMAL","COLOR"],transparentOpt=["NORMAL","COLOR","TRANSPARENT"],e&&(materialOpt.push("USE_IBL"),transparentOpt.push("USE_IBL")),pixelShader=initShader(pixelOpt),materialShader=initShader(materialOpt),colorShader=initShader(colorOpt),transparentShader=initShader(transparentOpt)}function deleteShaders(){gl.deleteProgram(transparentShader),gl.deleteProgram(colorShader),gl.deleteProgram(materialShader),gl.deleteProgram(pixelShader)}function saveAttributes(){let e=window.top.document.asygl2[alpha];e.gl=gl,e.nlights=Lights.length,e.Nmaterials=Nmaterials,e.maxMaterials=maxMaterials,e.pixelShader=pixelShader,e.materialShader=materialShader,e.colorShader=colorShader,e.transparentShader=transparentShader}function restoreAttributes(){let e=window.top.document.asygl2[alpha];gl=e.gl,nlights=e.nlights,Nmaterials=e.Nmaterials,maxMaterials=e.maxMaterials,pixelShader=e.pixelShader,materialShader=e.materialShader,colorShader=e.colorShader,transparentShader=e.transparentShader}function webGL(e,t){let i;return ibl&&(webgl2=!0),webgl2&&(i=e.getContext("webgl2",{alpha:t})),i||(webgl2=!1,ibl=!1,i=e.getContext("webgl",{alpha:t})),i||alert("Could not initialize WebGL"),i}function initGL(){if(alpha=Background[3]<1,embedded){let e=window.top.document;null==e.asygl2&&(e.asygl2=Array(2)),context=canvas.getContext("2d"),offscreen2=e.offscreen2,offscreen2||(offscreen2=e.createElement("canvas"),e.offscreen2=offscreen2),e.asygl2[alpha]&&e.asygl2[alpha].gl?(restoreAttributes(),(Lights.length!=nlights||Math.min(Materials.length,maxMaterials)>Nmaterials)&&(initShaders(),saveAttributes())):(gl=webGL(offscreen2,alpha),initShaders(),e.asygl2[alpha]={},saveAttributes())}else gl=webGL(canvas,alpha),initShaders();indexExt=gl.getExtension("OES_element_index_uint"),TRIANGLES=gl.TRIANGLES,material0Data=new vertexBuffer(gl.POINTS),material1Data=new vertexBuffer(gl.LINES),materialData=new vertexBuffer,colorData=new vertexBuffer,transparentData=new vertexBuffer,triangleData=new vertexBuffer}function getShader(e,t,i,a=[]){let n=webgl2?"300 es":"100",r=Array(...a),s=[["nlights",0==wireframe?Lights.length:0],["Nmaterials",Nmaterials]],o=[["int","Nlights",Math.max(Lights.length,1)]];webgl2&&r.push("WEBGL2"),ibl&&s.push(["ROUGHNESS_STEP_COUNT",roughnessStepCount.toFixed(2)]),orthographic&&r.push("ORTHOGRAPHIC"),macros_str=s.map(e=>`#define ${e[0]} ${e[1]}`).join("\n"),define_str=r.map(e=>"#define "+e).join("\n"),const_str=o.map(e=>`const ${e[0]} ${e[1]}=${e[2]};`).join("\n"),ext_str=[].map(e=>`#extension ${e}: enable`).join("\n"),shaderSrc=`#version ${n}\n${ext_str}\n${define_str}\n${const_str}\n${macros_str}\n\n\n#ifdef GL_FRAGMENT_PRECISION_HIGH\nprecision highp float;\n#else\nprecision mediump float;\n#endif\n \n${t}\n `;let l=e.createShader(i);return e.shaderSource(l,shaderSrc),e.compileShader(l),e.getShaderParameter(l,e.COMPILE_STATUS)?l:(alert(e.getShaderInfoLog(l)),null)}function registerBuffer(e,t,i,a=gl.ARRAY_BUFFER){return e.length>0&&(0==t&&(t=gl.createBuffer(),i=!0),gl.bindBuffer(a,t),i&&gl.bufferData(a,e,gl.STATIC_DRAW)),t}function drawBuffer(e,t,i=e.indices){if(0==e.indices.length)return;let a=t!=pixelShader;setUniforms(e,t),null!=IBLDiffuseMap&&(gl.activeTexture(gl.TEXTURE0),gl.bindTexture(gl.TEXTURE_2D,IBLbdrfMap),gl.uniform1i(gl.getUniformLocation(t,"reflBRDFSampler"),0),gl.activeTexture(gl.TEXTURE1),gl.bindTexture(gl.TEXTURE_2D,IBLDiffuseMap),gl.uniform1i(gl.getUniformLocation(t,"diffuseSampler"),1),gl.activeTexture(gl.TEXTURE2),gl.bindTexture(gl.TEXTURE_2D,IBLReflMap),gl.uniform1i(gl.getUniformLocation(t,"reflImgSampler"),2));let n=remesh||e.partial||!e.rendered;e.verticesBuffer=registerBuffer(new Float32Array(e.vertices),e.verticesBuffer,n),gl.vertexAttribPointer(positionAttribute,3,gl.FLOAT,!1,a?24:16,0),a?Lights.length>0&&gl.vertexAttribPointer(normalAttribute,3,gl.FLOAT,!1,24,12):gl.vertexAttribPointer(widthAttribute,1,gl.FLOAT,!1,16,12),e.materialsBuffer=registerBuffer(new Int16Array(e.materialIndices),e.materialsBuffer,n),gl.vertexAttribPointer(materialAttribute,1,gl.SHORT,!1,2,0),t!=colorShader&&t!=transparentShader||(e.colorsBuffer=registerBuffer(new Uint8Array(e.colors),e.colorsBuffer,n),gl.vertexAttribPointer(colorAttribute,4,gl.UNSIGNED_BYTE,!0,0,0)),e.indicesBuffer=registerBuffer(indexExt?new Uint32Array(i):new Uint16Array(i),e.indicesBuffer,n,gl.ELEMENT_ARRAY_BUFFER),e.rendered=!0,gl.drawElements(a?wireframe?gl.LINES:e.type:gl.POINTS,i.length,indexExt?gl.UNSIGNED_INT:gl.UNSIGNED_SHORT,0)}class vertexBuffer{constructor(e){this.type=e||TRIANGLES,this.verticesBuffer=0,this.materialsBuffer=0,this.colorsBuffer=0,this.indicesBuffer=0,this.rendered=!1,this.partial=!1,this.clear()}clear(){this.vertices=[],this.materialIndices=[],this.colors=[],this.indices=[],this.nvertices=0,this.materials=[],this.materialTable=[]}vertex(e,t){return this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.materialIndices.push(materialIndex),this.nvertices++}Vertex(e,t,i=[0,0,0,0]){return this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.vertices.push(t[0]),this.vertices.push(t[1]),this.vertices.push(t[2]),this.materialIndices.push(materialIndex),this.colors.push(i[0]),this.colors.push(i[1]),this.colors.push(i[2]),this.colors.push(i[3]),this.nvertices++}vertex0(e,t){return this.vertices.push(e[0]),this.vertices.push(e[1]),this.vertices.push(e[2]),this.vertices.push(t),this.materialIndices.push(materialIndex),this.nvertices++}iVertex(e,t,i,a=[0,0,0,0]){let n=6*e;this.vertices[n]=t[0],this.vertices[n+1]=t[1],this.vertices[n+2]=t[2],this.vertices[n+3]=i[0],this.vertices[n+4]=i[1],this.vertices[n+5]=i[2],this.materialIndices[e]=materialIndex;let r=4*e;this.colors[r]=a[0],this.colors[r+1]=a[1],this.colors[r+2]=a[2],this.colors[r+3]=a[3],this.indices.push(e)}append(e){append(this.vertices,e.vertices),append(this.materialIndices,e.materialIndices),append(this.colors,e.colors),appendOffset(this.indices,e.indices,this.nvertices),this.nvertices+=e.nvertices}}function append(e,t){let i=e.length,a=t.length;e.length+=a;for(let n=0;n<a;++n)e[i+n]=t[n]}function appendOffset(e,t,i){let a=e.length,n=t.length;e.length+=t.length;for(let r=0;r<n;++r)e[a+r]=t[r]+i}class Geometry{constructor(){this.data=new vertexBuffer,this.Onscreen=!1,this.m=[]}offscreen(e){let t=projViewMat,i=e[0],a=i[0],n=i[1],r=i[2],s=1/(t[3]*a+t[7]*n+t[11]*r+t[15]);this.x=this.X=(t[0]*a+t[4]*n+t[8]*r+t[12])*s,this.y=this.Y=(t[1]*a+t[5]*n+t[9]*r+t[13])*s;for(let i=1,a=e.length;i<a;++i){let a=e[i],n=a[0],r=a[1],s=a[2],o=1/(t[3]*n+t[7]*r+t[11]*s+t[15]),l=(t[0]*n+t[4]*r+t[8]*s+t[12])*o,h=(t[1]*n+t[5]*r+t[9]*s+t[13])*o;l<this.x?this.x=l:l>this.X&&(this.X=l),h<this.y?this.y=h:h>this.Y&&(this.Y=h)}return(this.X<-1.01||this.x>1.01||this.Y<-1.01||this.y>1.01)&&(this.Onscreen=!1,!0)}T(e){let t=this.c[0],i=this.c[1],a=this.c[2],n=e[0]-t,r=e[1]-i,s=e[2]-a;return[n*normMat[0]+r*normMat[3]+s*normMat[6]+t,n*normMat[1]+r*normMat[4]+s*normMat[7]+i,n*normMat[2]+r*normMat[5]+s*normMat[8]+a]}Tcorners(e,t){return[this.T(e),this.T([e[0],e[1],t[2]]),this.T([e[0],t[1],e[2]]),this.T([e[0],t[1],t[2]]),this.T([t[0],e[1],e[2]]),this.T([t[0],e[1],t[2]]),this.T([t[0],t[1],e[2]]),this.T(t)]}setMaterial(e,t){null==e.materialTable[this.MaterialIndex]&&(e.materials.length>=Nmaterials&&(e.partial=!0,t()),e.materialTable[this.MaterialIndex]=e.materials.length,e.materials.push(Materials[this.MaterialIndex])),materialIndex=e.materialTable[this.MaterialIndex]}render(){let e;if(this.setMaterialIndex(),0==this.CenterIndex?e=corners(this.Min,this.Max):(this.c=Centers[this.CenterIndex-1],e=this.Tcorners(this.Min,this.Max)),this.offscreen(e))return this.data.clear(),void this.notRendered();let t,i=this.controlpoints;if(0==this.CenterIndex){if(!remesh&&this.Onscreen)return void this.append();t=i}else{let e=i.length;t=Array(e);for(let a=0;a<e;++a)t[a]=this.T(i[a])}let a=orthographic?1:this.Min[2]/maxBound[2],n=.75*Math.hypot(a*(viewParam.xmax-viewParam.xmin),a*(viewParam.ymax-viewParam.ymin))/size2;this.res2=n*n,this.Epsilon=.1*n,this.data.clear(),this.notRendered(),this.Onscreen=!0,this.process(t)}}class BezierPatch extends Geometry{constructor(e,t,i,a,n,r){super(),this.controlpoints=e,this.CenterIndex=t,this.MaterialIndex=i,this.Min=a,this.Max=n,this.color=r;let s=e.length;if(r){let e=r[0][3]+r[1][3]+r[2][3];this.transparent=16==s||4==s?e+r[3][3]<1020:e<765}else this.transparent=Materials[i].diffuse[3]<1;this.vertex=this.transparent?this.data.Vertex.bind(this.data):this.data.vertex.bind(this.data),this.L2norm(this.controlpoints)}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.color?this.setMaterial(colorData,drawColor):this.setMaterial(materialData,drawMaterial)}L2norm(e){let t=e[0];this.epsilon=0;let i=e.length;for(let a=1;a<i;++a)this.epsilon=Math.max(this.epsilon,abs2([e[a][0]-t[0],e[a][1]-t[1],e[a][2]-t[2]]));this.epsilon*=Number.EPSILON}processTriangle(e){let t=e[0],i=e[1],a=e[2],n=unit(cross([i[0]-t[0],i[1]-t[1],i[2]-t[2]],[a[0]-t[0],a[1]-t[1],a[2]-t[2]]));if(!this.offscreen([t,i,a])){let e,r,s;this.color?(e=this.data.Vertex(t,n,this.color[0]),r=this.data.Vertex(i,n,this.color[1]),s=this.data.Vertex(a,n,this.color[2])):(e=this.vertex(t,n),r=this.vertex(i,n),s=this.vertex(a,n)),0==wireframe?(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(s)):(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(r),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(e)),this.append()}}processQuad(e){let t=e[0],i=e[1],a=e[2],n=e[3],r=cross([i[0]-t[0],i[1]-t[1],i[2]-t[2]],[a[0]-i[0],a[1]-i[1],a[2]-i[2]]),s=cross([a[0]-n[0],a[1]-n[1],a[2]-n[2]],[n[0]-t[0],n[1]-t[1],n[2]-t[2]]),o=unit([r[0]+s[0],r[1]+s[1],r[2]+s[2]]);if(!this.offscreen([t,i,a,n])){let e,r,s,l;this.color?(e=this.data.Vertex(t,o,this.color[0]),r=this.data.Vertex(i,o,this.color[1]),s=this.data.Vertex(a,o,this.color[2]),l=this.data.Vertex(n,o,this.color[3])):(e=this.vertex(t,o),r=this.vertex(i,o),s=this.vertex(a,o),l=this.vertex(n,o)),0==wireframe?(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(s),this.data.indices.push(e),this.data.indices.push(s),this.data.indices.push(l)):(this.data.indices.push(e),this.data.indices.push(r),this.data.indices.push(r),this.data.indices.push(s),this.data.indices.push(s),this.data.indices.push(l),this.data.indices.push(l),this.data.indices.push(e)),this.append()}}curve(e,t,i,a,n){new BezierCurve([e[t],e[i],e[a],e[n]],0,materialIndex,this.Min,this.Max).render()}process(e){if(this.transparent&&1!=wireframe&&(materialIndex=this.color?-1-materialIndex:1+materialIndex),10==e.length)return this.process3(e);if(3==e.length)return this.processTriangle(e);if(4==e.length)return this.processQuad(e);if(1==wireframe)return this.curve(e,0,4,8,12),this.curve(e,12,13,14,15),this.curve(e,15,11,7,3),void this.curve(e,3,2,1,0);let t=e[0],i=e[3],a=e[12],n=e[15],r=this.normal(i,e[2],e[1],t,e[4],e[8],a);abs2(r)<this.epsilon&&(r=this.normal(i,e[2],e[1],t,e[13],e[14],n),abs2(r)<this.epsilon&&(r=this.normal(n,e[11],e[7],i,e[4],e[8],a)));let s=this.normal(t,e[4],e[8],a,e[13],e[14],n);abs2(s)<this.epsilon&&(s=this.normal(t,e[4],e[8],a,e[11],e[7],i),abs2(s)<this.epsilon&&(s=this.normal(i,e[2],e[1],t,e[13],e[14],n)));let o=this.normal(a,e[13],e[14],n,e[11],e[7],i);abs2(o)<this.epsilon&&(o=this.normal(a,e[13],e[14],n,e[2],e[1],t),abs2(o)<this.epsilon&&(o=this.normal(t,e[4],e[8],a,e[11],e[7],i)));let l=this.normal(n,e[11],e[7],i,e[2],e[1],t);if(abs2(l)<this.epsilon&&(l=this.normal(n,e[11],e[7],i,e[4],e[8],a),abs2(l)<this.epsilon&&(l=this.normal(a,e[13],e[14],n,e[2],e[1],t))),this.color){let h=this.color[0],c=this.color[1],d=this.color[2],m=this.color[3],f=this.data.Vertex(t,r,h),u=this.data.Vertex(a,s,c),p=this.data.Vertex(n,o,d),g=this.data.Vertex(i,l,m);this.Render(e,f,u,p,g,t,a,n,i,!1,!1,!1,!1,h,c,d,m)}else{let h=this.vertex(t,r),c=this.vertex(a,s),d=this.vertex(n,o),m=this.vertex(i,l);this.Render(e,h,c,d,m,t,a,n,i,!1,!1,!1,!1)}this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):this.color?colorData.append(this.data):materialData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:this.color?colorData.rendered=!1:materialData.rendered=!1}Render(e,t,i,a,n,r,s,o,l,h,c,d,m,f,u,p,g){let v=this.Distance(e);if(v[0]<this.res2&&v[1]<this.res2)this.offscreen([r,s,o])||(0==wireframe?(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a))),this.offscreen([r,o,l])||(0==wireframe?(this.data.indices.push(t),this.data.indices.push(a),this.data.indices.push(n)):(this.data.indices.push(a),this.data.indices.push(n),this.data.indices.push(n),this.data.indices.push(t)));else{if(this.offscreen(e))return;let x=e[0],w=e[3],M=e[12],b=e[15];if(v[0]<this.res2){let v=new Split3(x,e[1],e[2],w),T=new Split3(e[4],e[5],e[6],e[7]),S=new Split3(e[8],e[9],e[10],e[11]),R=new Split3(M,e[13],e[14],b),I=[x,v.m0,v.m3,v.m5,e[4],T.m0,T.m3,T.m5,e[8],S.m0,S.m3,S.m5,M,R.m0,R.m3,R.m5],A=[v.m5,v.m4,v.m2,w,T.m5,T.m4,T.m2,e[7],S.m5,S.m4,S.m2,e[11],R.m5,R.m4,R.m2,b],E=this.normal(I[12],I[13],I[14],I[15],I[11],I[7],I[3]);abs2(E)<=this.epsilon&&(E=this.normal(I[12],I[13],I[14],I[15],I[2],I[1],I[0]),abs2(E)<=this.epsilon&&(E=this.normal(I[0],I[4],I[8],I[12],I[11],I[7],I[3])));let P=this.normal(A[3],A[2],A[1],A[0],A[4],A[8],A[12]);abs2(P)<=this.epsilon&&(P=this.normal(A[3],A[2],A[1],A[0],A[13],A[14],A[15]),abs2(P)<=this.epsilon&&(P=this.normal(A[15],A[11],A[7],A[3],A[4],A[8],A[12])));let L=this.Epsilon,D=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,e[13],e[14],b)<this.res2){let e=unit(this.differential(A[12],A[8],A[4],A[0]));D=[D[0]-L*e[0],D[1]-L*e[1],D[2]-L*e[2]]}else D=I[15];let y=[.5*(l[0]+r[0]),.5*(l[1]+r[1]),.5*(l[2]+r[2])];if(!m)if(m=Straightness(x,e[1],e[2],w)<this.res2){let e=unit(this.differential(I[3],I[7],I[11],I[15]));y=[y[0]-L*e[0],y[1]-L*e[1],y[2]-L*e[2]]}else y=A[0];if(f){let e=Array(4),v=Array(4);for(let t=0;t<4;++t)e[t]=.5*(u[t]+p[t]),v[t]=.5*(g[t]+f[t]);let x=this.data.Vertex(D,E,e),w=this.data.Vertex(y,P,v);this.Render(I,t,i,x,w,r,s,D,y,h,c,!1,m,f,u,e,v),this.Render(A,w,x,a,n,y,D,o,l,!1,c,d,m,v,e,p,g)}else{let e=this.vertex(D,E),f=this.vertex(y,P);this.Render(I,t,i,e,f,r,s,D,y,h,c,!1,m),this.Render(A,f,e,a,n,y,D,o,l,!1,c,d,m)}return}if(v[1]<this.res2){let v=new Split3(x,e[4],e[8],M),T=new Split3(e[1],e[5],e[9],e[13]),S=new Split3(e[2],e[6],e[10],e[14]),R=new Split3(w,e[7],e[11],b),I=[x,e[1],e[2],w,v.m0,T.m0,S.m0,R.m0,v.m3,T.m3,S.m3,R.m3,v.m5,T.m5,S.m5,R.m5],A=[v.m5,T.m5,S.m5,R.m5,v.m4,T.m4,S.m4,R.m4,v.m2,T.m2,S.m2,R.m2,M,e[13],e[14],b],E=this.normal(I[0],I[4],I[8],I[12],I[13],I[14],I[15]);abs2(E)<=this.epsilon&&(E=this.normal(I[0],I[4],I[8],I[12],I[11],I[7],I[3]),abs2(E)<=this.epsilon&&(E=this.normal(I[3],I[2],I[1],I[0],I[13],I[14],I[15])));let P=this.normal(A[15],A[11],A[7],A[3],A[2],A[1],A[0]);abs2(P)<=this.epsilon&&(P=this.normal(A[15],A[11],A[7],A[3],A[4],A[8],A[12]),abs2(P)<=this.epsilon&&(P=this.normal(A[12],A[13],A[14],A[15],A[2],A[1],A[0])));let L=this.Epsilon,D=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])];if(!h)if(h=Straightness(x,e[4],e[8],M)<this.res2){let e=unit(this.differential(A[0],A[1],A[2],A[3]));D=[D[0]-L*e[0],D[1]-L*e[1],D[2]-L*e[2]]}else D=I[12];let y=[.5*(o[0]+l[0]),.5*(o[1]+l[1]),.5*(o[2]+l[2])];if(!d)if(d=Straightness(b,e[11],e[7],w)<this.res2){let e=unit(this.differential(I[15],I[14],I[13],I[12]));y=[y[0]-L*e[0],y[1]-L*e[1],y[2]-L*e[2]]}else y=A[3];if(f){let e=Array(4),v=Array(4);for(let t=0;t<4;++t)e[t]=.5*(f[t]+u[t]),v[t]=.5*(p[t]+g[t]);let x=this.data.Vertex(D,E,e),w=this.data.Vertex(y,P,v);this.Render(I,t,x,w,n,r,D,y,l,h,!1,d,m,f,e,v,g),this.Render(A,x,i,a,w,D,s,o,y,h,c,d,!1,e,u,p,v)}else{let e=this.vertex(D,E),f=this.vertex(y,P);this.Render(I,t,e,f,n,r,D,y,l,h,!1,d,m),this.Render(A,e,i,a,f,D,s,o,y,h,c,d,!1)}return}let T=new Split3(x,e[1],e[2],w),S=new Split3(e[4],e[5],e[6],e[7]),R=new Split3(e[8],e[9],e[10],e[11]),I=new Split3(M,e[13],e[14],b),A=new Split3(x,e[4],e[8],M),E=new Split3(T.m0,S.m0,R.m0,I.m0),P=new Split3(T.m3,S.m3,R.m3,I.m3),L=new Split3(T.m5,S.m5,R.m5,I.m5),D=new Split3(T.m4,S.m4,R.m4,I.m4),y=new Split3(T.m2,S.m2,R.m2,I.m2),O=new Split3(w,e[7],e[11],b),B=[x,T.m0,T.m3,T.m5,A.m0,E.m0,P.m0,L.m0,A.m3,E.m3,P.m3,L.m3,A.m5,E.m5,P.m5,L.m5],N=[A.m5,E.m5,P.m5,L.m5,A.m4,E.m4,P.m4,L.m4,A.m2,E.m2,P.m2,L.m2,M,I.m0,I.m3,I.m5],z=[L.m5,D.m5,y.m5,O.m5,L.m4,D.m4,y.m4,O.m4,L.m2,D.m2,y.m2,O.m2,I.m5,I.m4,I.m2,b],_=[T.m5,T.m4,T.m2,w,L.m0,D.m0,y.m0,O.m0,L.m3,D.m3,y.m3,O.m3,L.m5,D.m5,y.m5,O.m5],C=B[15],V=this.normal(B[0],B[4],B[8],B[12],B[13],B[14],B[15]);abs2(V)<this.epsilon&&(V=this.normal(B[0],B[4],B[8],B[12],B[11],B[7],B[3]),abs2(V)<this.epsilon&&(V=this.normal(B[3],B[2],B[1],B[0],B[13],B[14],B[15])));let U=this.normal(N[12],N[13],N[14],N[15],N[11],N[7],N[3]);abs2(U)<this.epsilon&&(U=this.normal(N[12],N[13],N[14],N[15],N[2],N[1],N[0]),abs2(U)<this.epsilon&&(U=this.normal(N[0],N[4],N[8],N[12],N[11],N[7],N[3])));let H=this.normal(z[15],z[11],z[7],z[3],z[2],z[1],z[0]);abs2(H)<this.epsilon&&(H=this.normal(z[15],z[11],z[7],z[3],z[4],z[8],z[12]),abs2(H)<this.epsilon&&(H=this.normal(z[12],z[13],z[14],z[15],z[2],z[1],z[0])));let F=this.normal(_[3],_[2],_[1],_[0],_[4],_[8],_[12]);abs2(F)<this.epsilon&&(F=this.normal(_[3],_[2],_[1],_[0],_[13],_[14],_[15]),abs2(F)<this.epsilon&&(F=this.normal(_[15],_[11],_[7],_[3],_[4],_[8],_[12])));let G=this.normal(z[3],z[2],z[1],C,z[4],z[8],z[12]),X=this.Epsilon,W=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])];if(!h)if(h=Straightness(x,e[4],e[8],M)<this.res2){let e=unit(this.differential(N[0],N[1],N[2],N[3]));W=[W[0]-X*e[0],W[1]-X*e[1],W[2]-X*e[2]]}else W=B[12];let j=[.5*(s[0]+o[0]),.5*(s[1]+o[1]),.5*(s[2]+o[2])];if(!c)if(c=Straightness(M,e[13],e[14],b)<this.res2){let e=unit(this.differential(z[12],z[8],z[4],z[0]));j=[j[0]-X*e[0],j[1]-X*e[1],j[2]-X*e[2]]}else j=N[15];let Z=[.5*(o[0]+l[0]),.5*(o[1]+l[1]),.5*(o[2]+l[2])];if(!d)if(d=Straightness(b,e[11],e[7],w)<this.res2){let e=unit(this.differential(_[15],_[14],_[13],_[12]));Z=[Z[0]-X*e[0],Z[1]-X*e[1],Z[2]-X*e[2]]}else Z=z[3];let k=[.5*(l[0]+r[0]),.5*(l[1]+r[1]),.5*(l[2]+r[2])];if(!m)if(m=Straightness(x,e[1],e[2],w)<this.res2){let e=unit(this.differential(B[3],B[7],B[11],B[15]));k=[k[0]-X*e[0],k[1]-X*e[1],k[2]-X*e[2]]}else k=_[0];if(f){let e=Array(4),v=Array(4),x=Array(4),w=Array(4),M=Array(4);for(let t=0;t<4;++t)e[t]=.5*(f[t]+u[t]),v[t]=.5*(u[t]+p[t]),x[t]=.5*(p[t]+g[t]),w[t]=.5*(g[t]+f[t]),M[t]=.5*(e[t]+x[t]);let b=this.data.Vertex(W,V,e),T=this.data.Vertex(j,U,v),S=this.data.Vertex(Z,H,x),R=this.data.Vertex(k,F,w),I=this.data.Vertex(C,G,M);this.Render(B,t,b,I,R,r,W,C,k,h,!1,!1,m,f,e,M,w),this.Render(N,b,i,T,I,W,s,j,C,h,c,!1,!1,e,u,v,M),this.Render(z,I,T,a,S,C,j,o,Z,!1,c,d,!1,M,v,p,x),this.Render(_,R,I,S,n,k,C,Z,l,!1,!1,d,m,w,M,x,g)}else{let e=this.vertex(W,V),f=this.vertex(j,U),u=this.vertex(Z,H),p=this.vertex(k,F),g=this.vertex(C,G);this.Render(B,t,e,g,p,r,W,C,k,h,!1,!1,m),this.Render(N,e,i,f,g,W,s,j,C,h,c,!1,!1),this.Render(z,g,f,a,u,C,j,o,Z,!1,c,d,!1),this.Render(_,p,g,u,n,k,C,Z,l,!1,!1,d,m)}}}process3(e){if(1==wireframe)return this.curve(e,0,1,3,6),this.curve(e,6,7,8,9),void this.curve(e,9,5,2,0);let t=e[0],i=e[6],a=e[9],n=this.normal(a,e[5],e[2],t,e[1],e[3],i),r=this.normal(t,e[1],e[3],i,e[7],e[8],a),s=this.normal(i,e[7],e[8],a,e[5],e[2],t);if(this.color){let o=this.color[0],l=this.color[1],h=this.color[2],c=this.data.Vertex(t,n,o),d=this.data.Vertex(i,r,l),m=this.data.Vertex(a,s,h);this.Render3(e,c,d,m,t,i,a,!1,!1,!1,o,l,h)}else{let o=this.vertex(t,n),l=this.vertex(i,r),h=this.vertex(a,s);this.Render3(e,o,l,h,t,i,a,!1,!1,!1)}this.data.indices.length>0&&this.append()}Render3(e,t,i,a,n,r,s,o,l,h,c,d,m){if(this.Distance3(e)<this.res2)this.offscreen([n,r,s])||(0==wireframe?(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(a)):(this.data.indices.push(t),this.data.indices.push(i),this.data.indices.push(i),this.data.indices.push(a),this.data.indices.push(a),this.data.indices.push(t)));else{if(this.offscreen(e))return;let f=e[0],u=e[1],p=e[2],g=e[3],v=e[4],x=e[5],w=e[6],M=e[7],b=e[8],T=e[9],S=[.5*(T[0]+x[0]),.5*(T[1]+x[1]),.5*(T[2]+x[2])],R=[.5*(T[0]+b[0]),.5*(T[1]+b[1]),.5*(T[2]+b[2])],I=[.5*(x[0]+p[0]),.5*(x[1]+p[1]),.5*(x[2]+p[2])],A=[.5*(b[0]+v[0]),.5*(b[1]+v[1]),.5*(b[2]+v[2])],E=[.5*(b[0]+M[0]),.5*(b[1]+M[1]),.5*(b[2]+M[2])],P=[.5*(p[0]+v[0]),.5*(p[1]+v[1]),.5*(p[2]+v[2])],L=[.5*(p[0]+f[0]),.5*(p[1]+f[1]),.5*(p[2]+f[2])],D=[.5*(v[0]+g[0]),.5*(v[1]+g[1]),.5*(v[2]+g[2])],y=[.5*(M[0]+w[0]),.5*(M[1]+w[1]),.5*(M[2]+w[2])],O=[.5*(f[0]+u[0]),.5*(f[1]+u[1]),.5*(f[2]+u[2])],B=[.5*(u[0]+g[0]),.5*(u[1]+g[1]),.5*(u[2]+g[2])],N=[.5*(g[0]+w[0]),.5*(g[1]+w[1]),.5*(g[2]+w[2])],z=[.5*(S[0]+I[0]),.5*(S[1]+I[1]),.5*(S[2]+I[2])],_=[.5*(R[0]+E[0]),.5*(R[1]+E[1]),.5*(R[2]+E[2])],C=[.5*(I[0]+L[0]),.5*(I[1]+L[1]),.5*(I[2]+L[2])],V=[.5*A[0]+.25*(v[0]+u[0]),.5*A[1]+.25*(v[1]+u[1]),.5*A[2]+.25*(v[2]+u[2])],U=[.5*(E[0]+y[0]),.5*(E[1]+y[1]),.5*(E[2]+y[2])],H=[.5*P[0]+.25*(v[0]+M[0]),.5*P[1]+.25*(v[1]+M[1]),.5*P[2]+.25*(v[2]+M[2])],F=[.25*(x[0]+v[0])+.5*D[0],.25*(x[1]+v[1])+.5*D[1],.25*(x[2]+v[2])+.5*D[2]],G=[.5*(O[0]+B[0]),.5*(O[1]+B[1]),.5*(O[2]+B[2])],X=[.5*(B[0]+N[0]),.5*(B[1]+N[1]),.5*(B[2]+N[2])],W=[.5*(H[0]+G[0]),.5*(H[1]+G[1]),.5*(H[2]+G[2])],j=[.5*(H[0]+X[0]),.5*(H[1]+X[1]),.5*(H[2]+X[2])],Z=[.5*(G[0]+X[0]),.5*(G[1]+X[1]),.5*(G[2]+X[2])],k=[.5*(F[0]+U[0]),.5*(F[1]+U[1]),.5*(F[2]+U[2])],Y=[.5*(_[0]+F[0]),.5*(_[1]+F[1]),.5*(_[2]+F[2])],q=[.5*(_[0]+U[0]),.5*(_[1]+U[1]),.5*(_[2]+U[2])],$=[.5*(z[0]+V[0]),.5*(z[1]+V[1]),.5*(z[2]+V[2])],K=[.5*(C[0]+V[0]),.5*(C[1]+V[1]),.5*(C[2]+V[2])],Q=[.5*(z[0]+C[0]),.5*(z[1]+C[1]),.5*(z[2]+C[2])],J=[f,O,L,G,[.5*(P[0]+O[0]),.5*(P[1]+O[1]),.5*(P[2]+O[2])],C,Z,W,K,Q],ee=[Z,X,j,N,[.5*(D[0]+y[0]),.5*(D[1]+y[1]),.5*(D[2]+y[2])],k,w,y,U,q],te=[Q,$,z,Y,[.5*(S[0]+A[0]),.5*(S[1]+A[1]),.5*(S[2]+A[2])],S,q,_,R,T],ie=[q,Y,k,$,[.25*(I[0]+E[0]+B[0]+v[0]),.25*(I[1]+E[1]+B[1]+v[1]),.25*(I[2]+E[2]+B[2]+v[2])],j,Q,K,W,Z],ae=this.normal(Z,j,k,q,Y,$,Q),ne=this.normal(q,Y,$,Q,K,W,Z),re=this.normal(Q,K,W,Z,j,k,q),se=this.Epsilon,oe=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])];if(!o)if(o=Straightness(w,M,b,T)<this.res2){let e=unit(this.sumdifferential(ie[0],ie[2],ie[5],ie[9],ie[1],ie[3],ie[6]));oe=[oe[0]-se*e[0],oe[1]-se*e[1],oe[2]-se*e[2]]}else oe=q;let le=[.5*(s[0]+n[0]),.5*(s[1]+n[1]),.5*(s[2]+n[2])];if(!l)if(l=Straightness(f,p,x,T)<this.res2){let e=unit(this.sumdifferential(ie[6],ie[3],ie[1],ie[0],ie[7],ie[8],ie[9]));le=[le[0]-se*e[0],le[1]-se*e[1],le[2]-se*e[2]]}else le=Q;let he=[.5*(n[0]+r[0]),.5*(n[1]+r[1]),.5*(n[2]+r[2])];if(!h)if(h=Straightness(f,u,g,w)<this.res2){let e=unit(this.sumdifferential(ie[9],ie[8],ie[7],ie[6],ie[5],ie[2],ie[0]));he=[he[0]-se*e[0],he[1]-se*e[1],he[2]-se*e[2]]}else he=Z;if(c){let e=Array(4),f=Array(4),u=Array(4);for(let t=0;t<4;++t)e[t]=.5*(d[t]+m[t]),f[t]=.5*(m[t]+c[t]),u[t]=.5*(c[t]+d[t]);let p=this.data.Vertex(oe,ae,e),g=this.data.Vertex(le,ne,f),v=this.data.Vertex(he,re,u);this.Render3(J,t,v,g,n,he,le,!1,l,h,c,u,f),this.Render3(ee,v,i,p,he,r,oe,o,!1,h,u,d,e),this.Render3(te,g,p,a,le,oe,s,o,l,!1,f,e,m),this.Render3(ie,p,g,v,oe,le,he,!1,!1,!1,e,f,u)}else{let e=this.vertex(oe,ae),c=this.vertex(le,ne),d=this.vertex(he,re);this.Render3(J,t,d,c,n,he,le,!1,l,h),this.Render3(ee,d,i,e,he,r,oe,o,!1,h),this.Render3(te,c,e,a,le,oe,s,o,l,!1),this.Render3(ie,e,c,d,oe,le,he,!1,!1,!1)}}}Distance(e){let t=e[0],i=e[3],a=e[12],n=e[15],r=Flatness(t,a,i,n);r=Math.max(Straightness(t,e[4],e[8],a)),r=Math.max(r,Straightness(e[1],e[5],e[9],e[13])),r=Math.max(r,Straightness(i,e[7],e[11],n)),r=Math.max(r,Straightness(e[2],e[6],e[10],e[14]));let s=Flatness(t,i,a,n);return s=Math.max(s,Straightness(t,e[1],e[2],i)),s=Math.max(s,Straightness(e[4],e[5],e[6],e[7])),s=Math.max(s,Straightness(e[8],e[9],e[10],e[11])),s=Math.max(s,Straightness(a,e[13],e[14],n)),[r,s]}Distance3(e){let t=e[0],i=e[4],a=e[6],n=e[9],r=abs2([(t[0]+a[0]+n[0])*(1/3)-i[0],(t[1]+a[1]+n[1])*(1/3)-i[1],(t[2]+a[2]+n[2])*(1/3)-i[2]]);return r=Math.max(r,Straightness(t,e[1],e[3],a)),r=Math.max(r,Straightness(t,e[2],e[5],n)),Math.max(r,Straightness(a,e[7],e[8],n))}differential(e,t,i,a){let n=[3*(t[0]-e[0]),3*(t[1]-e[1]),3*(t[2]-e[2])];return abs2(n)>this.epsilon?n:(n=bezierPP(e,t,i),abs2(n)>this.epsilon?n:bezierPPP(e,t,i,a))}sumdifferential(e,t,i,a,n,r,s){let o=this.differential(e,t,i,a),l=this.differential(e,n,r,s);return[o[0]+l[0],o[1]+l[1],o[2]+l[2]]}normal(e,t,i,a,n,r,s){let o=3*(n[0]-a[0]),l=3*(n[1]-a[1]),h=3*(n[2]-a[2]),c=3*(i[0]-a[0]),d=3*(i[1]-a[1]),m=3*(i[2]-a[2]),f=[l*m-h*d,h*c-o*m,o*d-l*c];if(abs2(f)>this.epsilon)return f;let u=[c,d,m],p=[o,l,h],g=bezierPP(a,i,t),v=bezierPP(a,n,r),x=cross(v,u),w=cross(p,g);if(f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon)return f;let M=bezierPPP(a,i,t,e),b=bezierPPP(a,n,r,s);x=cross(p,M),w=cross(b,u);let T=cross(v,g);return f=[x[0]+w[0]+T[0],x[1]+w[1]+T[1],x[2]+w[2]+T[2]],abs2(f)>this.epsilon?f:(x=cross(b,g),w=cross(v,M),f=[x[0]+w[0],x[1]+w[1],x[2]+w[2]],abs2(f)>this.epsilon?f:cross(b,M))}}class BezierCurve extends Geometry{constructor(e,t,i,a,n){super(),this.controlpoints=e,this.CenterIndex=t,this.MaterialIndex=i,this.Min=a,this.Max=n}setMaterialIndex(){this.setMaterial(material1Data,drawMaterial1)}processLine(e){let t=e[0],i=e[1];if(!this.offscreen([t,i])){let e=[0,0,1];this.data.indices.push(this.data.vertex(t,e)),this.data.indices.push(this.data.vertex(i,e)),this.append()}}process(e){if(2==e.length)return this.processLine(e);let t=e[0],i=e[1],a=e[2],n=e[3],r=this.normal(bezierP(t,i),bezierPP(t,i,a)),s=this.normal(bezierP(a,n),bezierPP(n,a,i)),o=this.data.vertex(t,r),l=this.data.vertex(n,s);this.Render(e,o,l),this.data.indices.length>0&&this.append()}append(){material1Data.append(this.data)}notRendered(){material1Data.rendered=!1}Render(e,t,i){let a=e[0],n=e[1],r=e[2],s=e[3];if(Straightness(a,n,r,s)<this.res2)this.offscreen([a,s])||(this.data.indices.push(t),this.data.indices.push(i));else{if(this.offscreen(e))return;let o=[.5*(a[0]+n[0]),.5*(a[1]+n[1]),.5*(a[2]+n[2])],l=[.5*(n[0]+r[0]),.5*(n[1]+r[1]),.5*(n[2]+r[2])],h=[.5*(r[0]+s[0]),.5*(r[1]+s[1]),.5*(r[2]+s[2])],c=[.5*(o[0]+l[0]),.5*(o[1]+l[1]),.5*(o[2]+l[2])],d=[.5*(l[0]+h[0]),.5*(l[1]+h[1]),.5*(l[2]+h[2])],m=[.5*(c[0]+d[0]),.5*(c[1]+d[1]),.5*(c[2]+d[2])],f=[a,o,c,m],u=[m,d,h,s],p=this.normal(bezierPh(a,n,r,s),bezierPPh(a,n,r,s)),g=this.data.vertex(m,p);this.Render(f,t,g),this.Render(u,g,i)}}normal(e,t){let i=dot(e,e),a=dot(e,t);return[i*t[0]-a*e[0],i*t[1]-a*e[1],i*t[2]-a*e[2]]}}class Pixel extends Geometry{constructor(e,t,i,a,n){super(),this.controlpoint=e,this.width=t,this.CenterIndex=0,this.MaterialIndex=i,this.Min=a,this.Max=n}setMaterialIndex(){this.setMaterial(material0Data,drawMaterial0)}process(e){this.data.indices.push(this.data.vertex0(this.controlpoint,this.width)),this.append()}append(){material0Data.append(this.data)}notRendered(){material0Data.rendered=!1}}class Triangles extends Geometry{constructor(e,t,i,a){super(),this.CenterIndex=e,this.MaterialIndex=t,this.Min=i,this.Max=a,this.controlpoints=Positions,this.Normals=Normals,this.Colors=Colors,this.Indices=Indices,Positions=[],Normals=[],Colors=[],Indices=[],this.transparent=Materials[this.MaterialIndex].diffuse[3]<1}setMaterialIndex(){this.transparent?this.setMaterial(transparentData,drawTransparent):this.setMaterial(triangleData,drawTriangle)}process(e){this.data.vertices=new Array(6*e.length),materialIndex=this.Colors.length>0?-1-materialIndex:1+materialIndex;for(let t=0,i=this.Indices.length;t<i;++t){let i=this.Indices[t],a=i[0],n=e[a[0]],r=e[a[1]],s=e[a[2]];if(!this.offscreen([n,r,s])){let e=i.length>1?i[1]:a;if(e&&0!=e.length||(e=a),this.Colors.length>0){let t=i.length>2?i[2]:a;t&&0!=t.length||(t=a);let o=this.Colors[t[0]],l=this.Colors[t[1]],h=this.Colors[t[2]];this.transparent|=o[3]+l[3]+h[3]<765,0==wireframe?(this.data.iVertex(a[0],n,this.Normals[e[0]],o),this.data.iVertex(a[1],r,this.Normals[e[1]],l),this.data.iVertex(a[2],s,this.Normals[e[2]],h)):(this.data.iVertex(a[0],n,this.Normals[e[0]],o),this.data.iVertex(a[1],r,this.Normals[e[1]],l),this.data.iVertex(a[1],r,this.Normals[e[1]],l),this.data.iVertex(a[2],s,this.Normals[e[2]],h),this.data.iVertex(a[2],s,this.Normals[e[2]],h),this.data.iVertex(a[0],n,this.Normals[e[0]],o))}else 0==wireframe?(this.data.iVertex(a[0],n,this.Normals[e[0]]),this.data.iVertex(a[1],r,this.Normals[e[1]]),this.data.iVertex(a[2],s,this.Normals[e[2]])):(this.data.iVertex(a[0],n,this.Normals[e[0]]),this.data.iVertex(a[1],r,this.Normals[e[1]]),this.data.iVertex(a[1],r,this.Normals[e[1]]),this.data.iVertex(a[2],s,this.Normals[e[2]]),this.data.iVertex(a[2],s,this.Normals[e[2]]),this.data.iVertex(a[0],n,this.Normals[e[0]]))}}this.data.nvertices=e.length,this.data.indices.length>0&&this.append()}append(){this.transparent?transparentData.append(this.data):triangleData.append(this.data)}notRendered(){this.transparent?transparentData.rendered=!1:triangleData.rendered=!1}}function redrawScene(){initProjection(),setProjection(),remesh=!0,drawScene()}function home(){mat4.identity(rotMat),redrawScene()}let positionAttribute=0,normalAttribute=1,materialAttribute=2,colorAttribute=3,widthAttribute=4;function initShader(e=[]){let t=getShader(gl,vertex,gl.VERTEX_SHADER,e),i=getShader(gl,fragment,gl.FRAGMENT_SHADER,e),a=gl.createProgram();return gl.attachShader(a,t),gl.attachShader(a,i),gl.bindAttribLocation(a,positionAttribute,"position"),gl.bindAttribLocation(a,normalAttribute,"normal"),gl.bindAttribLocation(a,materialAttribute,"materialIndex"),gl.bindAttribLocation(a,colorAttribute,"color"),gl.bindAttribLocation(a,widthAttribute,"width"),gl.linkProgram(a),gl.getProgramParameter(a,gl.LINK_STATUS)||alert("Could not initialize shaders"),a}class Split3{constructor(e,t,i,a){this.m0=[.5*(e[0]+t[0]),.5*(e[1]+t[1]),.5*(e[2]+t[2])];let n=.5*(t[0]+i[0]),r=.5*(t[1]+i[1]),s=.5*(t[2]+i[2]);this.m2=[.5*(i[0]+a[0]),.5*(i[1]+a[1]),.5*(i[2]+a[2])],this.m3=[.5*(this.m0[0]+n),.5*(this.m0[1]+r),.5*(this.m0[2]+s)],this.m4=[.5*(n+this.m2[0]),.5*(r+this.m2[1]),.5*(s+this.m2[2])],this.m5=[.5*(this.m3[0]+this.m4[0]),.5*(this.m3[1]+this.m4[1]),.5*(this.m3[2]+this.m4[2])]}}function unit(e){let t=1/(Math.sqrt(e[0]*e[0]+e[1]*e[1]+e[2]*e[2])||1);return[e[0]*t,e[1]*t,e[2]*t]}function abs2(e){return e[0]*e[0]+e[1]*e[1]+e[2]*e[2]}function dot(e,t){return e[0]*t[0]+e[1]*t[1]+e[2]*t[2]}function cross(e,t){return[e[1]*t[2]-e[2]*t[1],e[2]*t[0]-e[0]*t[2],e[0]*t[1]-e[1]*t[0]]}function bezierP(e,t){return[t[0]-e[0],t[1]-e[1],t[2]-e[2]]}function bezierPP(e,t,i){return[3*(e[0]+i[0])-6*t[0],3*(e[1]+i[1])-6*t[1],3*(e[2]+i[2])-6*t[2]]}function bezierPPP(e,t,i,a){return[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])]}function bezierPh(e,t,i,a){return[i[0]+a[0]-e[0]-t[0],i[1]+a[1]-e[1]-t[1],i[2]+a[2]-e[2]-t[2]]}function bezierPPh(e,t,i,a){return[3*e[0]-5*t[0]+i[0]+a[0],3*e[1]-5*t[1]+i[1]+a[1],3*e[2]-5*t[2]+i[2]+a[2]]}function Straightness(e,t,i,a){let n=[1/3*(a[0]-e[0]),1/3*(a[1]-e[1]),1/3*(a[2]-e[2])];return Math.max(abs2([t[0]-n[0]-e[0],t[1]-n[1]-e[1],t[2]-n[2]-e[2]]),abs2([a[0]-n[0]-i[0],a[1]-n[1]-i[1],a[2]-n[2]-i[2]]))}function Flatness(e,t,i,a){let n=[t[0]-e[0],t[1]-e[1],t[2]-e[2]],r=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return Math.max(abs2(cross(n,unit(r))),abs2(cross(r,unit(n))))/9}function corners(e,t){return[e,[e[0],e[1],t[2]],[e[0],t[1],e[2]],[e[0],t[1],t[2]],[t[0],e[1],e[2]],[t[0],e[1],t[2]],[t[0],t[1],e[2]],t]}function minbound(e){return[Math.min(e[0][0],e[1][0],e[2][0],e[3][0],e[4][0],e[5][0],e[6][0],e[7][0]),Math.min(e[0][1],e[1][1],e[2][1],e[3][1],e[4][1],e[5][1],e[6][1],e[7][1]),Math.min(e[0][2],e[1][2],e[2][2],e[3][2],e[4][2],e[5][2],e[6][2],e[7][2])]}function maxbound(e){return[Math.max(e[0][0],e[1][0],e[2][0],e[3][0],e[4][0],e[5][0],e[6][0],e[7][0]),Math.max(e[0][1],e[1][1],e[2][1],e[3][1],e[4][1],e[5][1],e[6][1],e[7][1]),Math.max(e[0][2],e[1][2],e[2][2],e[3][2],e[4][2],e[5][2],e[6][2],e[7][2])]}function COBTarget(e,t){mat4.fromTranslation(T,[center.x,center.y,center.z]),mat4.invert(cjMatInv,T),mat4.multiply(e,t,cjMatInv),mat4.multiply(e,T,e)}function setUniforms(e,t){let i=t==pixelShader;gl.useProgram(t),gl.enableVertexAttribArray(positionAttribute),i&&gl.enableVertexAttribArray(widthAttribute);let a=!i&&Lights.length>0;if(a&&gl.enableVertexAttribArray(normalAttribute),gl.enableVertexAttribArray(materialAttribute),t.projViewMatUniform=gl.getUniformLocation(t,"projViewMat"),t.viewMatUniform=gl.getUniformLocation(t,"viewMat"),t.normMatUniform=gl.getUniformLocation(t,"normMat"),t!=colorShader&&t!=transparentShader||gl.enableVertexAttribArray(colorAttribute),a)for(let e=0;e<Lights.length;++e)Lights[e].setUniform(t,e);for(let i=0;i<e.materials.length;++i)e.materials[i].setUniform(t,i);gl.uniformMatrix4fv(t.projViewMatUniform,!1,projViewMat),gl.uniformMatrix4fv(t.viewMatUniform,!1,viewMat),gl.uniformMatrix3fv(t.normMatUniform,!1,normMat)}function handleMouseDown(e){zoomEnabled||enableZoom(),mouseDownOrTouchActive=!0,lastMouseX=e.clientX,lastMouseY=e.clientY}let pinchStart,touchStartTime,pinch=!1;function pinchDistance(e){return Math.hypot(e[0].pageX-e[1].pageX,e[0].pageY-e[1].pageY)}function handleTouchStart(e){e.preventDefault(),zoomEnabled||enableZoom();let t=e.targetTouches;swipe=rotate=pinch=!1,zooming||(1!=t.length||mouseDownOrTouchActive||(touchStartTime=(new Date).getTime(),touchId=t[0].identifier,lastMouseX=t[0].pageX,lastMouseY=t[0].pageY),2!=t.length||mouseDownOrTouchActive||(touchId=t[0].identifier,pinchStart=pinchDistance(t),pinch=!0))}function handleMouseUpOrTouchEnd(e){mouseDownOrTouchActive=!1}function rotateScene(e,t,i,a,n){if(e==i&&t==a)return;let[r,s]=arcball([e,-t],[i,-a]);mat4.fromRotation(T,2*n*ArcballFactor*r/Zoom,s),mat4.multiply(rotMat,T,rotMat)}function shiftScene(e,t,i,a){let n=1/Zoom;shift.x+=(i-e)*n*halfCanvasWidth,shift.y-=(a-t)*n*halfCanvasHeight}function panScene(e,t,i,a){orthographic?shiftScene(e,t,i,a):(center.x+=(i-e)*(viewParam.xmax-viewParam.xmin),center.y-=(a-t)*(viewParam.ymax-viewParam.ymin))}function updateViewMatrix(){COBTarget(viewMat,rotMat),mat4.translate(viewMat,viewMat,[center.x,center.y,0]),mat3.fromMat4(viewMat3,viewMat),mat3.invert(normMat,viewMat3),mat4.multiply(projViewMat,projMat,viewMat)}function capzoom(){let e=Math.sqrt(Number.MAX_VALUE),t=1/e;Zoom<=t&&(Zoom=t),Zoom>=e&&(Zoom=e),(1.5*Zoom<lastZoom||Zoom>1.5*lastZoom)&&(remesh=!0,lastZoom=Zoom)}function zoomImage(e){let t=zoomStep*halfCanvasHeight*e;const i=Math.log(.1*Number.MAX_VALUE)/Math.log(zoomFactor);Math.abs(t)<i&&(Zoom*=zoomFactor**t,capzoom())}function normMouse(e){let t=e[0],i=e[1],a=Math.hypot(t,i);return a>1&&(denom=1/a,t*=denom,i*=denom),[t,i,Math.sqrt(Math.max(1-i*i-t*t,0))]}function arcball(e,t){let i=normMouse(e),a=normMouse(t),n=dot(i,a);return[n>1?0:n<-1?pi:Math.acos(n),unit(cross(i,a))]}function zoomScene(e,t,i,a){zoomImage(t-a)}const DRAGMODE_ROTATE=1,DRAGMODE_SHIFT=2,DRAGMODE_ZOOM=3,DRAGMODE_PAN=4;function processDrag(e,t,i,a=1){let n;switch(i){case 1:n=rotateScene;break;case 2:n=shiftScene;break;case 3:n=zoomScene;break;case 4:n=panScene;break;default:n=(e,t,i,a)=>{}}n((lastMouseX-halfCanvasWidth)/halfCanvasWidth,(lastMouseY-halfCanvasHeight)/halfCanvasHeight,(e-halfCanvasWidth)/halfCanvasWidth,(t-halfCanvasHeight)/halfCanvasHeight,a),lastMouseX=e,lastMouseY=t,setProjection(),drawScene()}let zoomEnabled=0;function enableZoom(){zoomEnabled=1,canvas.addEventListener("wheel",handleMouseWheel,!1)}function disableZoom(){zoomEnabled=0,canvas.removeEventListener("wheel",handleMouseWheel,!1)}function handleKey(e){if(zoomEnabled||enableZoom(),embedded&&zoomEnabled&&27==e.keyCode)return void disableZoom();let t=[];switch(e.key){case"x":t=[1,0,0];break;case"y":t=[0,1,0];break;case"z":t=[0,0,1];break;case"h":home();break;case"m":++wireframe,3==wireframe&&(wireframe=0),2!=wireframe&&(embedded||deleteShaders(),initShaders(ibl)),remesh=!0,drawScene();break;case"+":case"=":case">":expand();break;case"-":case"_":case"<":shrink()}t.length>0&&(mat4.rotate(rotMat,rotMat,.1,t),updateViewMatrix(),drawScene())}function setZoom(){capzoom(),setProjection(),drawScene()}function handleMouseWheel(e){e.preventDefault(),e.deltaY<0?Zoom*=zoomFactor:Zoom/=zoomFactor,setZoom()}function handleMouseMove(e){if(!mouseDownOrTouchActive)return;let t,i=e.clientX,a=e.clientY;t=e.getModifierState("Control")?2:e.getModifierState("Shift")?3:e.getModifierState("Alt")?4:1,processDrag(i,a,t)}let zooming=!1,swipe=!1,rotate=!1;function handleTouchMove(e){if(e.preventDefault(),zooming)return;let t=e.targetTouches;if(!pinch&&1==t.length&&touchId==t[0].identifier){let e=t[0].pageX,i=t[0].pageY,a=e-lastMouseX,n=i-lastMouseY,r=a*a+n*n<=shiftHoldDistance*shiftHoldDistance;if(r&&!swipe&&!rotate&&(new Date).getTime()-touchStartTime>shiftWaitTime&&(navigator.vibrate&&window.navigator.vibrate(vibrateTime),swipe=!0),swipe)processDrag(e,i,2);else if(!r){rotate=!0,processDrag(t[0].pageX,t[0].pageY,1,.5)}}if(pinch&&!swipe&&2==t.length&&touchId==t[0].identifier){let e=pinchDistance(t),i=e-pinchStart;zooming=!0,i*=zoomPinchFactor,i>zoomPinchCap&&(i=zoomPinchCap),i<-zoomPinchCap&&(i=-zoomPinchCap),zoomImage(i/size2),pinchStart=e,swipe=rotate=zooming=!1,setProjection(),drawScene()}}let pixelShader,materialShader,colorShader,transparentShader,zbuffer=[];function transformVertices(e){let t=viewMat[2],i=viewMat[6],a=viewMat[10];zbuffer.length=e.length;for(let n=0;n<e.length;++n){let r=6*n;zbuffer[n]=t*e[r]+i*e[r+1]+a*e[r+2]}}function drawMaterial0(){drawBuffer(material0Data,pixelShader),material0Data.clear()}function drawMaterial1(){drawBuffer(material1Data,materialShader),material1Data.clear()}function drawMaterial(){drawBuffer(materialData,materialShader),materialData.clear()}function drawColor(){drawBuffer(colorData,colorShader),colorData.clear()}function drawTriangle(){drawBuffer(triangleData,transparentShader),triangleData.rendered=!1,triangleData.clear()}function drawTransparent(){let e=transparentData.indices;if(wireframe>0)return drawBuffer(transparentData,transparentShader,e),void transparentData.clear();if(e.length>0){transformVertices(transparentData.vertices);let t=e.length/3,i=Array(t).fill().map((e,t)=>t);i.sort((function(t,i){let a=3*t;Ia=e[a],Ib=e[a+1],Ic=e[a+2];let n=3*i;return IA=e[n],IB=e[n+1],IC=e[n+2],zbuffer[Ia]+zbuffer[Ib]+zbuffer[Ic]<zbuffer[IA]+zbuffer[IB]+zbuffer[IC]?-1:1}));let a=Array(e.length);for(let n=0;n<t;++n){let t=3*i[n];a[3*n]=e[t],a[3*n+1]=e[t+1],a[3*n+2]=e[t+2]}gl.depthMask(!1),drawBuffer(transparentData,transparentShader,a),transparentData.rendered=!1,gl.depthMask(!0)}transparentData.clear()}function drawBuffers(){drawMaterial0(),drawMaterial1(),drawMaterial(),drawColor(),drawTriangle(),drawTransparent(),requestAnimationFrame(drawBuffers)}function drawScene(){embedded&&(offscreen2.width=canvasWidth,offscreen2.height=canvasHeight,setViewport()),gl.clearColor(Background[0],Background[1],Background[2],Background[3]),gl.clear(gl.COLOR_BUFFER_BIT|gl.DEPTH_BUFFER_BIT);for(let e=0;e<P.length;++e)P[e].render();drawBuffers(),embedded&&(context.clearRect(0,0,canvasWidth,canvasHeight),context.drawImage(offscreen2,0,0)),0==wireframe&&(remesh=!1)}function setDimensions(e,t,i,a){let n=e/t,r=1/Zoom,s=(i/e+viewportShift[0])*Zoom,o=(a/t+viewportShift[1])*Zoom;if(orthographic){let e=maxBound[0]-minBound[0],t=maxBound[1]-minBound[1];if(e<t*n){let e=.5*t*n*r,i=2*e*s,a=t*r*o;viewParam.xmin=-e-i,viewParam.xmax=e-i,viewParam.ymin=minBound[1]*r-a,viewParam.ymax=maxBound[1]*r-a}else{let t=.5*e/(n*Zoom),i=e*r*s,a=2*t*o;viewParam.xmin=minBound[0]*r-i,viewParam.xmax=maxBound[0]*r-i,viewParam.ymin=-t-a,viewParam.ymax=t-a}}else{let e=H*r,t=e*n,i=2*t*s,a=2*e*o;viewParam.xmin=-t-i,viewParam.xmax=t-i,viewParam.ymin=-e-a,viewParam.ymax=e-a}}function setProjection(){setDimensions(canvasWidth,canvasHeight,shift.x,shift.y),(orthographic?mat4.ortho:mat4.frustum)(projMat,viewParam.xmin,viewParam.xmax,viewParam.ymin,viewParam.ymax,-viewParam.zmax,-viewParam.zmin),updateViewMatrix()}function initProjection(){H=-Math.tan(.5*angleOfView)*maxBound[2],center.x=center.y=0,center.z=.5*(minBound[2]+maxBound[2]),lastZoom=Zoom=zoom0,viewParam.zmin=minBound[2],viewParam.zmax=maxBound[2],shift.x=shift.y=0}function setViewport(){gl.viewportWidth=canvasWidth,gl.viewportHeight=canvasHeight,gl.viewport(.5*(canvas.width-canvasWidth),.5*(canvas.height-canvasHeight),canvasWidth,canvasHeight),gl.scissor(0,0,canvas.width,canvas.height)}function setCanvas(){embedded&&(canvas.width=offscreen2.width=canvasWidth,canvas.height=offscreen2.height=canvasHeight),size2=Math.hypot(canvasWidth,canvasHeight),halfCanvasWidth=.5*canvas.width,halfCanvasHeight=.5*canvas.height,ArcballFactor=1+8*Math.hypot(viewportMargin[0],viewportMargin[1])/size2}function setsize(e,t){e>maxViewportWidth&&(e=maxViewportWidth),t>maxViewportHeight&&(t=maxViewportHeight),shift.x*=e/canvasWidth,shift.y*=t/canvasHeight,canvasWidth=e,canvasHeight=t,setCanvas(),setViewport(),setProjection(),remesh=!0}function resize(){if(zoom0=initialZoom,absolute&&!embedded)canvasWidth=canvasWidth0*window.devicePixelRatio,canvasHeight=canvasHeight0*window.devicePixelRatio;else{let e=canvasWidth0/canvasHeight0;canvasWidth=Math.max(window.innerWidth-10,10),canvasHeight=Math.max(window.innerHeight-10,10),!orthographic&&canvasWidth<canvasHeight*e&&(zoom0*=canvasWidth/(canvasHeight*e))}canvas.width=canvasWidth,canvas.height=canvasHeight;window.innerWidth,window.innerHeight;viewportShift[0]/=zoom0,viewportShift[1]/=zoom0,setsize(canvasWidth,canvasHeight),redrawScene()}function expand(){Zoom*=zoomFactor,setZoom()}function shrink(){Zoom/=zoomFactor,setZoom()}class Align{constructor(e,t){if(this.center=e,t){let e=t[0],i=t[1];this.ct=Math.cos(e),this.st=Math.sin(e),this.cp=Math.cos(i),this.sp=Math.sin(i)}}T0(e){return[e[0]+this.center[0],e[1]+this.center[1],e[2]+this.center[2]]}T(e){let t=e[0],i=e[1],a=e[2],n=t*this.ct+a*this.st;return[n*this.cp-i*this.sp+this.center[0],n*this.sp+i*this.cp+this.center[1],-t*this.st+a*this.ct+this.center[2]]}}function Tcorners(e,t,i){let a=[e(t),e([t[0],t[1],i[2]]),e([t[0],i[1],t[2]]),e([t[0],i[1],i[2]]),e([i[0],t[1],t[2]]),e([i[0],t[1],i[2]]),e([i[0],i[1],t[2]]),e(i)];return[minbound(a),maxbound(a)]}function material(e,t,i,a,n,r){Materials.push(new Material(e,t,i,a,n,r))}function patch(e,t,i,a,n,r){P.push(new BezierPatch(e,t,i,a,n,r))}function curve(e,t,i,a,n){P.push(new BezierCurve(e,t,i,a,n))}function pixel(e,t,i,a,n){P.push(new Pixel(e,t,i,a,n))}function triangles(e,t,i,a){P.push(new Triangles(e,t,i,a))}function sphere(e,t,i,n,r){let s,o,l,h,c,d,m=.524670512339254,f=.595936986722291,u=.954967051233925,p=.0820155480083437,g=.996685028842544,v=.0549670512339254,x=.998880711874577,w=.0405017186586849,M=[[[1,0,0],[1,0,m],[f,0,u],[p,0,g],[1,a,0],[1,a,m],[f,a*f,u],[p,a*p,g],[a,1,0],[a,1,m],[a*f,f,u],[a*p,p,g],[0,1,0],[0,1,m],[0,f,u],[0,p,g]],[[p,0,g],[p,a*p,g],[v,0,x],[a*p,p,g],[w,w,1],[.05*a,0,1],[0,p,g],[0,v,x],[0,.05*a,1],[0,0,1]]],b=new Align(e,r);function T(e){let t=Array(e.length);for(let i=0;i<e.length;++i){let a=e[i];t[i]=c([s*a[0],o*a[1],l*a[2]])}return t}r?(h=1,d=0,c=b.T.bind(b)):(h=-1,d=-t,c=b.T0.bind(b));let S=Tcorners(c,[-t,-t,d],[t,t,t]),R=S[0],I=S[1];for(let e=-1;e<=1;e+=2){s=e*t;for(let e=-1;e<=1;e+=2){o=e*t;for(let e=h;e<=1;e+=2){l=e*t;for(let e=0;e<2;++e)P.push(new BezierPatch(T(M[e]),i,n,R,I))}}}}let a=4/3*(Math.sqrt(2)-1);function disk(e,t,i,n,r){let s=1-2*a/3,o=[[1,0,0],[1,-a,0],[a,-1,0],[0,-1,0],[1,a,0],[s,0,0],[0,-s,0],[-a,-1,0],[a,1,0],[0,s,0],[-s,0,0],[-1,-a,0],[0,1,0],[-a,1,0],[-1,a,0],[-1,0,0]],l=new Align(e,r);let h=Tcorners(l.T.bind(l),[-t,-t,0],[t,t,0]);P.push(new BezierPatch(function(e){let i=Array(e.length);for(let a=0;a<e.length;++a){let n=e[a];i[a]=l.T([t*n[0],t*n[1],0])}return i}(o),i,n,h[0],h[1]))}function cylinder(e,t,i,n,r,s,o){let l,h,c=[[1,0,0],[1,0,1/3],[1,0,2/3],[1,0,1],[1,a,0],[1,a,1/3],[1,a,2/3],[1,a,1],[a,1,0],[a,1,1/3],[a,1,2/3],[a,1,1],[0,1,0],[0,1,1/3],[0,1,2/3],[0,1,1]],d=new Align(e,s);function m(e){let t=Array(e.length);for(let a=0;a<e.length;++a){let n=e[a];t[a]=d.T([l*n[0],h*n[1],i*n[2]])}return t}let f=Tcorners(d.T.bind(d),[-t,-t,0],[t,t,i]),u=f[0],p=f[1];for(let e=-1;e<=1;e+=2){l=e*t;for(let e=-1;e<=1;e+=2)h=e*t,P.push(new BezierPatch(m(c),n,r,u,p))}if(o){let t=d.T([0,0,i]);P.push(new BezierCurve([e,t],n,r,e,t))}}function rmf(e,t,i,a,n){class r{constructor(e,t,i){this.p=e,this.r=t,this.t=i,this.s=cross(i,t)}}let s=Number.EPSILON*Math.max(abs2(e),abs2(t),abs2(i),abs2(a));function o(n){if(1==n){let n=[a[0]-i[0],a[1]-i[1],a[2]-i[2]];return abs2(n)>s?unit(n):(n=[2*i[0]-t[0]-a[0],2*i[1]-t[1]-a[1],2*i[2]-t[2]-a[2]],abs2(n)>s?unit(n):[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])])}let r=[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])],o=[2*(e[0]+i[0])-4*t[0],2*(e[1]+i[1])-4*t[1],2*(e[2]+i[2])-4*t[2]],l=[t[0]-e[0],t[1]-e[1],t[2]-e[2]],h=n*n,c=[r[0]*h+o[0]*n+l[0],r[1]*h+o[1]*n+l[1],r[2]*h+o[2]*n+l[2]];return abs2(c)>s?unit(c):(h=2*n,c=[r[0]*h+o[0],r[1]*h+o[1],r[2]*h+o[2]],abs2(c)>s?unit(c):unit(r))}let l=Array(n.length),h=[t[0]-e[0],t[1]-e[1],t[2]-e[2]];abs2(h)<s&&(h=[e[0]-2*t[0]+i[0],e[1]-2*t[1]+i[1],e[2]-2*t[2]+i[2]],abs2(h)<s&&(h=[a[0]-e[0]+3*(t[0]-i[0]),a[1]-e[1]+3*(t[1]-i[1]),a[2]-e[2]+3*(t[2]-i[2])])),h=unit(h);let c=function(e){let t=cross(e,[0,1,0]),i=Number.EPSILON*abs2(e);return abs2(t)>i?unit(t):(t=cross(e,[0,0,1]),abs2(t)>i?unit(t):[1,0,0])}(h);l[0]=new r(e,c,h);for(let s=1;s<n.length;++s){let h=l[s-1],c=n[s],d=1-c,m=d*d,f=m*d,u=3*c;m*=u,d*=u*c;let p=c*c*c,g=[f*e[0]+m*t[0]+d*i[0]+p*a[0],f*e[1]+m*t[1]+d*i[1]+p*a[1],f*e[2]+m*t[2]+d*i[2]+p*a[2]],v=[g[0]-h.p[0],g[1]-h.p[1],g[2]-h.p[2]];if(0!=v[0]||0!=v[1]||0!=v[2]){let e=h.r,t=unit(v),i=h.t,a=dot(t,i),n=[i[0]-2*a*t[0],i[1]-2*a*t[1],i[2]-2*a*t[2]];i=o(c);let d=2*dot(t,e),m=[e[0]-d*t[0],e[1]-d*t[1],e[2]-d*t[2]],f=unit([i[0]-n[0],i[1]-n[1],i[2]-n[2]]),u=2*dot(f,m);m=[m[0]-u*f[0],m[1]-u*f[1],m[2]-u*f[2]],l[s]=new r(g,unit(m),unit(i))}else l[s]=l[s-1]}return l}function tube(e,t,i,n,r,s,o){let l=rmf(e[0],e[1],e[2],e[3],[0,1/3,2/3,1]),h=a*t,c=[[t,0],[t,h],[h,t],[0,t]];function d(t,a,o,h){let d=Array(16);for(let i=0;i<4;++i){let n=l[i],r=n.r[0],s=n.s[0],m=r*t+s*a,f=r*o+s*h;r=n.r[1],s=n.s[1];let u=r*t+s*a,p=r*o+s*h;r=n.r[2],s=n.s[2];let g=r*t+s*a,v=r*o+s*h,x=e[i],w=x[0];w1=x[1],w2=x[2];for(let e=0;e<4;++e){let t=c[e],a=t[0],n=t[1];d[4*i+e]=[m*a+f*n+w,u*a+p*n+w1,g*a+v*n+w2]}}P.push(new BezierPatch(d,i,n,r,s))}d(1,0,0,1),d(0,-1,1,0),d(-1,0,0,-1),d(0,1,-1,0),o&&P.push(new BezierCurve(e,i,n,r,s))}async function getReq(e){return(await fetch(e)).arrayBuffer()}function rgb(e){return e.getBytes().filter((e,t)=>t%4!=3)}function createTexture(e,t,i=gl.RGB16F){let a=e.width(),n=e.height(),r=gl.createTexture();return gl.activeTexture(gl.TEXTURE0+t),gl.bindTexture(gl.TEXTURE_2D,r),gl.pixelStorei(gl.UNPACK_ALIGNMENT,1),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR),gl.texImage2D(gl.TEXTURE_2D,0,i,a,n,0,gl.RGB,gl.FLOAT,rgb(e)),r}async function initIBL(){let e=imageURL+image+"/";function t(e){return new Promise(t=>setTimeout(t,e))}for(;!Module.EXRLoader;)await t(0);promises=[getReq(imageURL+"refl.exr").then(e=>{let t=new Module.EXRLoader(e);IBLbdrfMap=createTexture(t,0)}),getReq(e+"diffuse.exr").then(e=>{let t=new Module.EXRLoader(e);IBLDiffuseMap=createTexture(t,1)})],refl_promise=[],refl_promise.push(getReq(e+"refl0.exr"));for(let t=1;t<=roughnessStepCount;++t)refl_promise.push(getReq(e+"refl"+t+"w.exr"));finished_promise=Promise.all(refl_promise).then(e=>{let t=gl.createTexture();gl.activeTexture(gl.TEXTURE0+2),gl.pixelStorei(gl.UNPACK_ALIGNMENT,1),gl.bindTexture(gl.TEXTURE_2D,t),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAX_LEVEL,e.length-1),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MIN_FILTER,gl.LINEAR_MIPMAP_LINEAR),gl.texParameteri(gl.TEXTURE_2D,gl.TEXTURE_MAG_FILTER,gl.LINEAR),gl.texParameterf(gl.TEXTURE_2D,gl.TEXTURE_MIN_LOD,0),gl.texParameterf(gl.TEXTURE_2D,gl.TEXTURE_MAX_LOD,roughnessStepCount);for(let t=0;t<e.length;++t){let i=new Module.EXRLoader(e[t]);gl.texImage2D(gl.TEXTURE_2D,t,gl.RGB16F,i.width(),i.height(),0,gl.RGB,gl.FLOAT,rgb(i))}IBLReflMap=t}),promises.push(finished_promise),await Promise.all(promises)}function webGLStart(){canvas=document.getElementById("Asymptote"),embedded=window.top.document!=document,initGL(),gl.enable(gl.BLEND),gl.blendFunc(gl.SRC_ALPHA,gl.ONE_MINUS_SRC_ALPHA),gl.enable(gl.DEPTH_TEST),gl.enable(gl.SCISSOR_TEST),canvas.onmousedown=handleMouseDown,document.onmouseup=handleMouseUpOrTouchEnd,document.onmousemove=handleMouseMove,canvas.onkeydown=handleKey,embedded||enableZoom(),canvas.addEventListener("touchstart",handleTouchStart,!1),canvas.addEventListener("touchend",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchcancel",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchleave",handleMouseUpOrTouchEnd,!1),canvas.addEventListener("touchmove",handleTouchMove,!1),document.addEventListener("keydown",handleKey,!1),canvasWidth0=canvasWidth,canvasHeight0=canvasHeight,mat4.identity(rotMat),0!=window.innerWidth&&0!=window.innerHeight&&resize(),window.addEventListener("resize",resize,!1),ibl&&initIBL().then(SetIBL).then(redrawScene)}
diff --git a/graphics/asymptote/base/x11colors.asy b/graphics/asymptote/base/x11colors.asy
index 77e0401f06..eb65e5346f 100644
--- a/graphics/asymptote/base/x11colors.asy
+++ b/graphics/asymptote/base/x11colors.asy
@@ -1,4 +1,4 @@
-pen rgbint(int r, int g, int b)
+pen rgbint(int r, int g, int b)
{
return rgb(r/255,g/255,b/255);
}