summaryrefslogtreecommitdiff
path: root/graphics
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2021-12-29 03:01:06 +0000
committerNorbert Preining <norbert@preining.info>2021-12-29 03:01:06 +0000
commitdce1a2a6ecd9971433b4ee24c9d36b124cc1280e (patch)
tree051072f1ec49fbe350e7f88309ab293d1806e121 /graphics
parentecdf859b6ce481abfd530425dcf6f0f764bd0001 (diff)
CTAN sync 202112290301
Diffstat (limited to 'graphics')
-rw-r--r--graphics/asymptote/ChangeLog50
-rw-r--r--graphics/asymptote/ReleaseNotes5
-rw-r--r--graphics/asymptote/asy-keywords.el2
-rw-r--r--graphics/asymptote/asymptote.spec2
-rw-r--r--graphics/asymptote/base/v3dheadertypes.asy2
-rw-r--r--graphics/asymptote/base/v3dtypes.asy2
-rw-r--r--graphics/asymptote/base/webgl/asygl.js2
-rw-r--r--graphics/asymptote/binaries/i386-windows/README62
-rwxr-xr-xgraphics/asymptote/binaries/i386-windows/cygwin1.dllbin3276463 -> 0 bytes
-rw-r--r--graphics/asymptote/binaries/i386-windows/texlive/README5
-rwxr-xr-xgraphics/asymptote/configure18
-rw-r--r--graphics/asymptote/configure.ac2
-rw-r--r--graphics/asymptote/doc/CAD.pdfbin198823 -> 198824 bytes
-rw-r--r--graphics/asymptote/doc/FAQ/asy-faq.info2
-rw-r--r--graphics/asymptote/doc/TeXShopAndAsymptote.pdfbin81162 -> 81162 bytes
-rw-r--r--graphics/asymptote/doc/asy-latex.pdfbin206973 -> 206973 bytes
-rw-r--r--graphics/asymptote/doc/asyRefCard.pdfbin121145 -> 121145 bytes
-rw-r--r--graphics/asymptote/doc/asymptote.pdfbin1241549 -> 1241553 bytes
-rw-r--r--graphics/asymptote/doc/png/asymptote.info4
-rw-r--r--graphics/asymptote/revision.cc2
-rw-r--r--graphics/asymptote/v3dheadertypes.h2
-rw-r--r--graphics/asymptote/v3dheadertypes.py2
-rw-r--r--graphics/asymptote/v3dtypes.h2
-rw-r--r--graphics/asymptote/v3dtypes.py2
-rw-r--r--graphics/asymptote/webgl/gl.js70
-rw-r--r--graphics/pgf/contrib/yquant/README.md17
-rw-r--r--graphics/pgf/contrib/yquant/doc/yquant-doc.pdfbin712093 -> 994303 bytes
-rw-r--r--graphics/pgf/contrib/yquant/doc/yquant-doc.tex1694
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-circuit.tex32
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-config.tex35
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-env.tex303
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-lang.tex15
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-prepare.tex2
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-registers.tex63
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-shapes.tex7
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant-tools.tex2
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquant.sty8
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquantlanguage-groups.sty8
-rw-r--r--graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty12
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/Changes6
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/Changes.txt5
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/README.md16
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.pdfbin0 -> 228546 bytes
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.tex (renamed from graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.tex)110
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.pdfbin0 -> 233412 bytes
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.tex (renamed from graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.tex)102
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/latex/pst-geometrictools.sty (renamed from graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools.sty)0
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.pdfbin214485 -> 0 bytes
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.pdfbin268998 -> 0 bytes
-rw-r--r--graphics/pstricks/contrib/pst-geometrictools/tex/pst-geometrictools.tex (renamed from graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools.tex)2469
50 files changed, 3561 insertions, 1583 deletions
diff --git a/graphics/asymptote/ChangeLog b/graphics/asymptote/ChangeLog
index 23f6922e9b..b3ed362b49 100644
--- a/graphics/asymptote/ChangeLog
+++ b/graphics/asymptote/ChangeLog
@@ -1,3 +1,53 @@
+commit f28852ba9da596dd61f3755e67bc2a52d76c1fef
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 17:40:27 2021 -0700
+
+ Update asygl.
+
+commit 9217e347a01f1a8f2b095a1aac1d319e12a21306
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 17:37:28 2021 -0700
+
+ Look for an existing webgl context if webgl2 is unavailable.
+
+commit 72154e5aadd39f9c58586bd0fdc0ac51d68373b7
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 16:43:08 2021 -0700
+
+ Update asygl.
+
+commit e6359241240166ee8ec48d022ee858313892dfac
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 16:40:35 2021 -0700
+
+ Support embedding of webgl and webgl2 scenes on the same page.
+
+commit 0539672ff6043da10a0afce946be9f1bc1809e65
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 15:20:03 2021 -0700
+
+ Revert "Revert webgl2 default in asygl library."
+
+ This reverts commit 045d59d63b429d28bd133c1a550a36fa1726be60.
+
+commit 3f78b81efd7129f0617eff4fcf60d6ab8f670ded
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 14:39:24 2021 -0700
+
+ Update asygl.
+
+commit 045d59d63b429d28bd133c1a550a36fa1726be60
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 14:37:06 2021 -0700
+
+ Revert webgl2 default in asygl library.
+
+commit 4d04f9d75313e24d8987806b6ecae6f2c3660ac5
+Author: John Bowman <bowman@ualberta.ca>
+Date: Mon Dec 27 13:12:53 2021 -0700
+
+ Increment version to 2.73.
+
commit d1641723495c25a4cf84da33a477078903c2ef4c
Author: John Bowman <bowman@ualberta.ca>
Date: Mon Dec 27 12:42:11 2021 -0700
diff --git a/graphics/asymptote/ReleaseNotes b/graphics/asymptote/ReleaseNotes
index fb0f2b579c..fb9044a2fa 100644
--- a/graphics/asymptote/ReleaseNotes
+++ b/graphics/asymptote/ReleaseNotes
@@ -1,3 +1,8 @@
+Release Notes for Version 2.73
+
+The asygl library was updated to support embedding of WebGL and WebGL2 scenes
+on the same page.
+
Release Notes for Version 2.72
WebGL2 is enabled by default only for examples that use image-based lighting.
diff --git a/graphics/asymptote/asy-keywords.el b/graphics/asymptote/asy-keywords.el
index bd6d7ff4a3..d351611f0f 100644
--- a/graphics/asymptote/asy-keywords.el
+++ b/graphics/asymptote/asy-keywords.el
@@ -2,7 +2,7 @@
;; This file is automatically generated by asy-list.pl.
;; Changes will be overwritten.
;;
-(defvar asy-keywords-version "2.72")
+(defvar asy-keywords-version "2.73")
(defvar asy-keyword-name '(
and controls tension atleast curl if else while for do return break continue struct typedef new access import unravel from include quote static public private restricted this explicit true false null cycle newframe operator ))
diff --git a/graphics/asymptote/asymptote.spec b/graphics/asymptote/asymptote.spec
index 63ef30356d..199ca1755a 100644
--- a/graphics/asymptote/asymptote.spec
+++ b/graphics/asymptote/asymptote.spec
@@ -3,7 +3,7 @@
%global __python %{__python3}
Name: asymptote
-Version: 2.72
+Version: 2.73
Release: 1%{?dist}
Summary: Descriptive vector graphics language
diff --git a/graphics/asymptote/base/v3dheadertypes.asy b/graphics/asymptote/base/v3dheadertypes.asy
index 765d678080..cc78dfd4f4 100644
--- a/graphics/asymptote/base/v3dheadertypes.asy
+++ b/graphics/asymptote/base/v3dheadertypes.asy
@@ -1,6 +1,6 @@
// Enum class for v3dheadertypes
// AUTO-GENERATED from v3dheadertypes.csv
-// Generated at 2021-12-27 12:46:04.747922
+// Generated at 2021-12-27 17:52:27.156438
struct v3dheadertypes
{
diff --git a/graphics/asymptote/base/v3dtypes.asy b/graphics/asymptote/base/v3dtypes.asy
index b5f19cd5cd..270e28faeb 100644
--- a/graphics/asymptote/base/v3dtypes.asy
+++ b/graphics/asymptote/base/v3dtypes.asy
@@ -1,6 +1,6 @@
// Enum class for v3dtypes
// AUTO-GENERATED from v3dtypes.csv
-// Generated at 2021-12-27 12:46:04.684643
+// Generated at 2021-12-27 17:52:27.075241
struct v3dtypes
{
diff --git a/graphics/asymptote/base/webgl/asygl.js b/graphics/asymptote/base/webgl/asygl.js
index 8e02dcfbda..3f8cc84a38 100644
--- a/graphics/asymptote/base/webgl/asygl.js
+++ b/graphics/asymptote/base/webgl/asygl.js
@@ -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="\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)}
+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,offscreen,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=webgl2?window.top.document.asygl2[alpha]:window.top.document.asygl[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=webgl2?window.top.document.asygl2[alpha]:window.top.document.asygl[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 webgl2&&(i=e.getContext("webgl2",{alpha:t}),embedded&&!i)?(webgl2=!1,ibl=!1,initGL(!1),null):(i||(webgl2=!1,ibl=!1,i=e.getContext("webgl",{alpha:t})),i||alert("Could not initialize WebGL"),i)}function initGL(e=!0){if(ibl&&(webgl2=!0),alpha=Background[3]<1,embedded){let t=window.top.document;if(e&&(context=canvas.getContext("2d")),offscreen=webgl2?t.offscreen2:t.offscreen,offscreen||(offscreen=t.createElement("canvas"),webgl2?t.offscreen2=offscreen:t.offscreen=offscreen),webgl2?t.asygl2||(t.asygl2=Array(2)):t.asygl||(t.asygl=Array(2)),asygl=webgl2?t.asygl2:t.asygl,asygl[alpha]&&asygl[alpha].gl)restoreAttributes(),(Lights.length!=nlights||Math.min(Materials.length,maxMaterials)>Nmaterials)&&(initShaders(),saveAttributes());else{if(rc=webGL(offscreen,alpha),!rc)return;gl=rc,initShaders(),webgl2?t.asygl2[alpha]={}:t.asygl[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 G=this.normal(_[3],_[2],_[1],_[0],_[4],_[8],_[12]);abs2(G)<this.epsilon&&(G=this.normal(_[3],_[2],_[1],_[0],_[13],_[14],_[15]),abs2(G)<this.epsilon&&(G=this.normal(_[15],_[11],_[7],_[3],_[4],_[8],_[12])));let F=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,G,w),I=this.data.Vertex(C,F,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,G),g=this.vertex(C,F);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])],G=[.25*(x[0]+v[0])+.5*D[0],.25*(x[1]+v[1])+.5*D[1],.25*(x[2]+v[2])+.5*D[2]],F=[.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]+F[0]),.5*(H[1]+F[1]),.5*(H[2]+F[2])],j=[.5*(H[0]+X[0]),.5*(H[1]+X[1]),.5*(H[2]+X[2])],Z=[.5*(F[0]+X[0]),.5*(F[1]+X[1]),.5*(F[2]+X[2])],k=[.5*(G[0]+U[0]),.5*(G[1]+U[1]),.5*(G[2]+U[2])],Y=[.5*(_[0]+G[0]),.5*(_[1]+G[1]),.5*(_[2]+G[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,F,[.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&&(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 e=0;e<P.length;++e)P[e].render();drawBuffers(),embedded&&(context.clearRect(0,0,canvasWidth,canvasHeight),context.drawImage(offscreen,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=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(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/binaries/i386-windows/README b/graphics/asymptote/binaries/i386-windows/README
deleted file mode 100644
index 693b14efaa..0000000000
--- a/graphics/asymptote/binaries/i386-windows/README
+++ /dev/null
@@ -1,62 +0,0 @@
- ASYMPTOTE
- Copyright 2004-21 Andy Hammerlindl, John Bowman, and Tom Prince
-
-Asymptote is a powerful descriptive vector graphics language for technical
-drawing, inspired by MetaPost but with an improved C++-like
-syntax. Asymptote provides for figures the same high-quality level of
-typesetting that LaTeX does for scientific text.
-
-Installation instructions, documentation, binaries, and source code are
-available at:
-
-https://asymptote.sourceforge.io
-
-Bugs/Patches/Feature Requests can be submitted to
-
-https://github.com/vectorgraphics/asymptote/issues
-
-Questions and comments should be sent to the Asymptote Forum:
-
-https://sourceforge.net/p/asymptote/discussion/409349
-
-All source files in the Asymptote project, unless explicitly noted otherwise,
-are released under version 3 (or later) of the GNU Lesser General Public
-License (see the files LICENSE.LESSER and LICENSE in the top-level source
-directory).
-
-========================================================================
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU Lesser General Public License as published by
-the Free Software Foundation; either version 3 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public License
-along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-========================================================================
-
-Note that the MSWindows executable version of Asymptote can only be
-released under the GNU General Public License (GPL) as it is linked against
-the GNU Scientific Library, GNU Readline library, and other GPL
-libraries. This version of Asymptote also ships with the cygwin1.dll libraries
-noted below.
-
-========================================================================
-
-Source code for the x86_64 and i386 3.3.3 cygwin1.dll libraries is
-available under the GPL license:
-https://cygwin.com/snapshots/
-
-Source for various icons is available under the MIT license from
-https://github.com/driftyco/ionicons/archive/v2.0.1.zip
-https://github.com/iconic/open-iconic/archive/master.zip
-under the CC-BY-SA 4.0 license:
-http://www.entypo.com/
-and under a CC license:
-http://www.zondicons.com/zondicons.zip
diff --git a/graphics/asymptote/binaries/i386-windows/cygwin1.dll b/graphics/asymptote/binaries/i386-windows/cygwin1.dll
deleted file mode 100755
index 1a4f38221e..0000000000
--- a/graphics/asymptote/binaries/i386-windows/cygwin1.dll
+++ /dev/null
Binary files differ
diff --git a/graphics/asymptote/binaries/i386-windows/texlive/README b/graphics/asymptote/binaries/i386-windows/texlive/README
deleted file mode 100644
index 41576b36f4..0000000000
--- a/graphics/asymptote/binaries/i386-windows/texlive/README
+++ /dev/null
@@ -1,5 +0,0 @@
-The Asymptote executable for MSWindows can only be released under the GNU
-General Public License (GPL) as it is linked against the GNU Scientific
-Library, GNU Readline library, WolfSSL, and other GPL libraries. The Asymptote
-source itself is released under the GNU Lesser General Public License.
-
diff --git a/graphics/asymptote/configure b/graphics/asymptote/configure
index 1473361be0..4f79832c4c 100755
--- a/graphics/asymptote/configure
+++ b/graphics/asymptote/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for Asymptote 2.72.
+# Generated by GNU Autoconf 2.69 for Asymptote 2.73.
#
# Report bugs to <https://sourceforge.net/projects/asymptote>.
#
@@ -580,8 +580,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='Asymptote'
PACKAGE_TARNAME='asymptote'
-PACKAGE_VERSION='2.72'
-PACKAGE_STRING='Asymptote 2.72'
+PACKAGE_VERSION='2.73'
+PACKAGE_STRING='Asymptote 2.73'
PACKAGE_BUGREPORT='https://sourceforge.net/projects/asymptote'
PACKAGE_URL=''
@@ -1302,7 +1302,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures Asymptote 2.72 to adapt to many kinds of systems.
+\`configure' configures Asymptote 2.73 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1368,7 +1368,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of Asymptote 2.72:";;
+ short | recursive ) echo "Configuration of Asymptote 2.73:";;
esac
cat <<\_ACEOF
@@ -1486,7 +1486,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-Asymptote configure 2.72
+Asymptote configure 2.73
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2072,7 +2072,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by Asymptote $as_me 2.72, which was
+It was created by Asymptote $as_me 2.73, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -9464,7 +9464,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by Asymptote $as_me 2.72, which was
+This file was extended by Asymptote $as_me 2.73, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -9526,7 +9526,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-Asymptote config.status 2.72
+Asymptote config.status 2.73
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff --git a/graphics/asymptote/configure.ac b/graphics/asymptote/configure.ac
index e3d0f175ff..9949b14ab3 100644
--- a/graphics/asymptote/configure.ac
+++ b/graphics/asymptote/configure.ac
@@ -3,7 +3,7 @@
# this file.
AC_PREREQ(2)
-AC_INIT([Asymptote],[2.72],[https://sourceforge.net/projects/asymptote])
+AC_INIT([Asymptote],[2.73],[https://sourceforge.net/projects/asymptote])
VERSION=$PACKAGE_VERSION
AC_SUBST(VERSION)
m4_include([ax_pthread.m4])
diff --git a/graphics/asymptote/doc/CAD.pdf b/graphics/asymptote/doc/CAD.pdf
index 14d1114072..5154e96903 100644
--- a/graphics/asymptote/doc/CAD.pdf
+++ b/graphics/asymptote/doc/CAD.pdf
Binary files differ
diff --git a/graphics/asymptote/doc/FAQ/asy-faq.info b/graphics/asymptote/doc/FAQ/asy-faq.info
index 9293c651c7..9e1d3239ad 100644
--- a/graphics/asymptote/doc/FAQ/asy-faq.info
+++ b/graphics/asymptote/doc/FAQ/asy-faq.info
@@ -10,7 +10,7 @@ END-INFO-DIR-ENTRY
File: asy-faq.info, Node: Top, Next: Question 1.1, Up: (dir)
ASYMPTOTE FREQUENTLY ASKED QUESTIONS
- 2021-12-27
+ 2021-12-28
This is the list of Frequently Asked Questions about Asymptote (asy).
diff --git a/graphics/asymptote/doc/TeXShopAndAsymptote.pdf b/graphics/asymptote/doc/TeXShopAndAsymptote.pdf
index bc39562057..3a71f1f16a 100644
--- a/graphics/asymptote/doc/TeXShopAndAsymptote.pdf
+++ b/graphics/asymptote/doc/TeXShopAndAsymptote.pdf
Binary files differ
diff --git a/graphics/asymptote/doc/asy-latex.pdf b/graphics/asymptote/doc/asy-latex.pdf
index b0b693c1ab..d4883f473b 100644
--- a/graphics/asymptote/doc/asy-latex.pdf
+++ b/graphics/asymptote/doc/asy-latex.pdf
Binary files differ
diff --git a/graphics/asymptote/doc/asyRefCard.pdf b/graphics/asymptote/doc/asyRefCard.pdf
index 91f0963562..c98ebc9cb7 100644
--- a/graphics/asymptote/doc/asyRefCard.pdf
+++ b/graphics/asymptote/doc/asyRefCard.pdf
Binary files differ
diff --git a/graphics/asymptote/doc/asymptote.pdf b/graphics/asymptote/doc/asymptote.pdf
index 2344714227..d6d333db9e 100644
--- a/graphics/asymptote/doc/asymptote.pdf
+++ b/graphics/asymptote/doc/asymptote.pdf
Binary files differ
diff --git a/graphics/asymptote/doc/png/asymptote.info b/graphics/asymptote/doc/png/asymptote.info
index 8e61eb0a97..c29e943982 100644
--- a/graphics/asymptote/doc/png/asymptote.info
+++ b/graphics/asymptote/doc/png/asymptote.info
@@ -1,7 +1,7 @@
This is asymptote.info, produced by makeinfo version 6.7 from
asymptote.texi.
-This file documents 'Asymptote', version 2.72.
+This file documents 'Asymptote', version 2.73.
<https://asymptote.sourceforge.io>
@@ -22,7 +22,7 @@ File: asymptote.info, Node: Top, Next: Description, Prev: (dir), Up: (dir)
Asymptote
*********
-This file documents 'Asymptote', version 2.72.
+This file documents 'Asymptote', version 2.73.
<https://asymptote.sourceforge.io>
diff --git a/graphics/asymptote/revision.cc b/graphics/asymptote/revision.cc
index fbdccf7c1b..542ace2426 100644
--- a/graphics/asymptote/revision.cc
+++ b/graphics/asymptote/revision.cc
@@ -1,2 +1,2 @@
-const char *REVISION="2.72";
+const char *REVISION="2.73";
const char *AsyGLVersion="1.01";
diff --git a/graphics/asymptote/v3dheadertypes.h b/graphics/asymptote/v3dheadertypes.h
index e27fa68c1f..a0b20aa22a 100644
--- a/graphics/asymptote/v3dheadertypes.h
+++ b/graphics/asymptote/v3dheadertypes.h
@@ -1,6 +1,6 @@
// Enum class for v3dheadertypes
// AUTO-GENERATED from v3dheadertypes.csv
-// Generated at 2021-12-27 12:44:53.701402
+// Generated at 2021-12-27 17:51:07.172154
namespace camp
{
diff --git a/graphics/asymptote/v3dheadertypes.py b/graphics/asymptote/v3dheadertypes.py
index a74f63fc4b..8c0a349bf4 100644
--- a/graphics/asymptote/v3dheadertypes.py
+++ b/graphics/asymptote/v3dheadertypes.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Enum class for v3dheadertypes
""" AUTO-GENERATED from v3dheadertypes.csv """
-# Generated at 2021-12-27 12:46:04.819978
+# Generated at 2021-12-27 17:52:27.321330
class v3dheadertypes:
v3dheadertypes_canvasWidth=1
diff --git a/graphics/asymptote/v3dtypes.h b/graphics/asymptote/v3dtypes.h
index 883d5c0499..d57a7a561e 100644
--- a/graphics/asymptote/v3dtypes.h
+++ b/graphics/asymptote/v3dtypes.h
@@ -1,6 +1,6 @@
// Enum class for v3dtypes
// AUTO-GENERATED from v3dtypes.csv
-// Generated at 2021-12-27 12:44:53.701233
+// Generated at 2021-12-27 17:51:07.172168
namespace camp
{
diff --git a/graphics/asymptote/v3dtypes.py b/graphics/asymptote/v3dtypes.py
index dcf83decf3..6fa9b38436 100644
--- a/graphics/asymptote/v3dtypes.py
+++ b/graphics/asymptote/v3dtypes.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
# Enum class for v3dtypes
""" AUTO-GENERATED from v3dtypes.csv """
-# Generated at 2021-12-27 12:46:04.824592
+# Generated at 2021-12-27 17:52:27.235343
class v3dtypes:
v3dtypes_material=1
diff --git a/graphics/asymptote/webgl/gl.js b/graphics/asymptote/webgl/gl.js
index a42ef6ab36..2cbf7e15c2 100644
--- a/graphics/asymptote/webgl/gl.js
+++ b/graphics/asymptote/webgl/gl.js
@@ -37,7 +37,7 @@ let canvas; // Rendering canvas
let gl; // WebGL rendering context
let alpha; // Is background opaque?
-let offscreen2; // Offscreen rendering canvas for embedded images
+let offscreen; // Offscreen rendering canvas for embedded images
let context; // 2D context for copying embedded offscreen images
let nlights=0; // Number of lights compiled in shader
@@ -190,7 +190,9 @@ function deleteShaders()
function saveAttributes()
{
- let a=window.top.document.asygl2[alpha];
+ let a=webgl2 ?
+ window.top.document.asygl2[alpha] :
+ window.top.document.asygl[alpha];
a.gl=gl;
a.nlights=Lights.length;
@@ -205,7 +207,9 @@ function saveAttributes()
function restoreAttributes()
{
- let a=window.top.document.asygl2[alpha];
+ let a=webgl2 ?
+ window.top.document.asygl2[alpha] :
+ window.top.document.asygl[alpha];
gl=a.gl;
nlights=a.nlights;
@@ -222,8 +226,15 @@ let indexExt;
function webGL(canvas,alpha) {
let gl;
- if(ibl) webgl2=true;
- if(webgl2) gl=canvas.getContext("webgl2",{alpha: alpha});
+ if(webgl2) {
+ gl=canvas.getContext("webgl2",{alpha: alpha});
+ if(embedded && !gl) {
+ webgl2=false;
+ ibl=false;
+ initGL(false); // Look for an existing webgl context
+ return null; // Skip remainder of parent call
+ }
+ }
if(!gl) {
webgl2=false;
ibl=false;
@@ -234,27 +245,44 @@ function webGL(canvas,alpha) {
return gl;
}
-function initGL()
+function initGL(outer=true)
{
+ if(ibl) webgl2=true;
+
alpha=Background[3] < 1;
if(embedded) {
let p=window.top.document;
- if(p.asygl2 == null)
- p.asygl2=Array(2);
+ if(outer) context=canvas.getContext("2d");
+ offscreen=webgl2 ? p.offscreen2 : p.offscreen;
+ if(!offscreen) {
+ offscreen=p.createElement("canvas");
+ if(webgl2)
+ p.offscreen2=offscreen;
+ else
+ p.offscreen=offscreen;
+ }
- context=canvas.getContext("2d");
- offscreen2=p.offscreen2;
- if(!offscreen2) {
- offscreen2=p.createElement("canvas");
- p.offscreen2=offscreen2;
+ if(webgl2) {
+ if(!p.asygl2)
+ p.asygl2=Array(2);
+ } else {
+ if(!p.asygl)
+ p.asygl=Array(2);
}
- if(!p.asygl2[alpha] || !p.asygl2[alpha].gl) {
- gl=webGL(offscreen2,alpha);
+ asygl=webgl2 ? p.asygl2 : p.asygl;
+
+ if(!asygl[alpha] || !asygl[alpha].gl) {
+ rc=webGL(offscreen,alpha);
+ if(rc) gl=rc;
+ else return;
initShaders();
- p.asygl2[alpha]={};
+ if(webgl2)
+ p.asygl2[alpha]={};
+ else
+ p.asygl[alpha]={};
saveAttributes();
} else {
restoreAttributes();
@@ -2635,8 +2663,8 @@ function drawBuffers()
function drawScene()
{
if(embedded) {
- offscreen2.width=canvasWidth;
- offscreen2.height=canvasHeight;
+ offscreen.width=canvasWidth;
+ offscreen.height=canvasHeight;
setViewport();
}
@@ -2650,7 +2678,7 @@ function drawScene()
if(embedded) {
context.clearRect(0,0,canvasWidth,canvasHeight);
- context.drawImage(offscreen2,0,0);
+ context.drawImage(offscreen,0,0);
}
if(wireframe == 0) remesh=false;
@@ -2731,8 +2759,8 @@ function setViewport()
function setCanvas()
{
if(embedded) {
- canvas.width=offscreen2.width=canvasWidth;
- canvas.height=offscreen2.height=canvasHeight;
+ canvas.width=offscreen.width=canvasWidth;
+ canvas.height=offscreen.height=canvasHeight;
}
size2=Math.hypot(canvasWidth,canvasHeight);
halfCanvasWidth=0.5*canvas.width;
diff --git a/graphics/pgf/contrib/yquant/README.md b/graphics/pgf/contrib/yquant/README.md
index 724ab32711..93e177ca28 100644
--- a/graphics/pgf/contrib/yquant/README.md
+++ b/graphics/pgf/contrib/yquant/README.md
@@ -5,9 +5,24 @@ yquant is a LaTeX package that allows to quickly draw quantum circuits. It bridg
yquant is a pure-LaTeX solution - i.e., it requires no external program - that introduces a logic oriented language and thus brings the best of both worlds together.
It builds on and interacts with TiKZ, which brings an enourmous flexibility for customization of individual circuit.
+Important features in the latest updates (for a much more complete list, see the documentation):
+- Support the `beamer` package (since 0.6)
+- New `text` gate, which replaces the common `[draw=none] box` situation (since 0.6)
+- Integration of all qpic examples in the manual, showcasing some very advanced circuits (since 0.6)
+- Simple interface for circuit equations, no more `subcircuit` hassling (since 0.5)
+- Measurement outputs can now directly control other gates, i.e., with a vertical classical line emanating from the measurement (since 0.4)
+- Automatically adjust vertical positions of wires also for multi-register gates (since 0.4-alpha)
+- Vertical alignment actually works for subcircuits (since 0.4-alpha)
+- Directly support circuits written in the `qasm` language (since 0.3)
+- Simple declaration of custom gates (since 0.2.1)
+- Support for subcircuits, though vertical alignment may be messed up (since 0.2)
+- Load circuits from files (since 0.2)
+- Native support for non-contiguous multi-qubit gates (since 0.1.2)
+- Extensive user-friendly support for register name ranges, lists (since 0.1.1)
+
A detailed reference with lots of examples is provided in the PDF version of this Readme. We will sketch some basic usage.
-Now yquant also understands circuits written in the qasm language and provides a simple interface for circuit equations!
+The arXiv runs on version 0.3.2 - please download the latest version from the releases section and include it in your submission.
Support the development:
- [![PayPal](https://img.shields.io/badge/donate-via%20PayPal-blue.svg?style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=UTR3MRBYJ825A&source=url)
diff --git a/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf b/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf
index baca7da540..9fefce4faf 100644
--- a/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf
+++ b/graphics/pgf/contrib/yquant/doc/yquant-doc.pdf
Binary files differ
diff --git a/graphics/pgf/contrib/yquant/doc/yquant-doc.tex b/graphics/pgf/contrib/yquant/doc/yquant-doc.tex
index b6c5e3057f..ac027a7101 100644
--- a/graphics/pgf/contrib/yquant/doc/yquant-doc.tex
+++ b/graphics/pgf/contrib/yquant/doc/yquant-doc.tex
@@ -190,6 +190,8 @@
\def\ee{{\symup e}}
\def\ketbra#1#2{\ket{#1}\!\bra{#2}}
+\robustify\bmod % unicode-math makes problems when \bmod is used within a box
+
\frenchspacing
\RequirePackage{scrlayer-scrpage,scrlayer-notecolumn}
\setcounter{tocdepth}{\subsectiontocdepth}
@@ -209,7 +211,7 @@
\noindent This manual introduces \Yquant, a \LaTeX\hyp only package that outputs quantum circuits.
They are entered using a human\hyp readable language that, even from the source code, allows for a fluent understanding of the logic that underlies the circuit.
\Yquant{} internally builds on \TikZ{} and can be easily combined with arbitrary \LaTeX{} code.
- More than fifty pages of examples complement the formal manual.
+ Almost one hundred pages of examples complement the formal manual.
\end{abstract}
\tableofcontents
@@ -217,7 +219,7 @@
This document outlines the scope and usage of the \Yquant{} package.
It contains both a reference and a huge number of examples.
\Yquant{} is a package that makes typesetting quantum circuits easy; the package is available on CTAN.
- This beta version~0.5.1 \emph{should} be stable and interfaces are not very likely to change in an incompatible way in the future.
+ This beta version~0.6 \emph{should} be stable and interfaces are not very likely to change in an incompatible way in the future.
\compat{New in 0.4}Sometimes, backwards\hyp incompatible changes are required or advisable, in which case a compatibility setting will allow to revert back to the old behavior (rather, to maximize compatibility, this is an opt\hyp in setting: unless you choose the new behavior, you will get the old one).
Please do report all issues and desirable additions on \href{https://github.com/projekter/yquant/issues}{GitHub}.
@@ -265,7 +267,7 @@
Additionally, the \tex!\xymatrix! syntax is also somewhat cryptic.
\pkg{qcircuit} provides some flexibility within the limits of \pkg{xy} as to configuring the output.
- Maintenance status: last update in 2018; and remember this is \pkg{xy} based, with last update in 2013.
+ Maintenance status: active (\href{https://github.com/CQuIC/qcircuit}{GitHub}); but remember this is \pkg{xy} based, with last update in 2013.
\item \pkg{quantikz} is a relatively recent package that, following the same grid\hyp based approach as \pkg{qcircuit}, instead builds on \TikZ{} as a backend.
As a consequence, it provides the full flexibility of customization that \TikZ{} offers, where hardly anything cannot be done.
It also reduces burdens of the \pkg{xy} syntax.
@@ -341,9 +343,9 @@
When starting a new document, it is recommended to leave out the compatibility key at first compilation.
\Yquant{} will then issue a warning from which you can infer the recommended setting, corresponding to the current version.
You should then pass the appropriate version to the \tex!\usepackage! command.
- For example, this manual corresponds to \tex!\usepackage[compat=0.4]{yquant}!.
+ For example, this manual corresponds to \tex!\usepackage[compat=0.6]{yquant}!.
- Allowed values for \texttt{compat} are \texttt{newest} (discouraged), which equals \texttt{0.4}, and \texttt{0.3} (default).
+ Allowed values for \texttt{compat} are \texttt{newest} (discouraged), which equals \texttt{0.6}, \texttt{0.4}, and \texttt{0.3} (default).
\end{warning}
\subsection{Starred vs. unstarred environment}
@@ -575,7 +577,8 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
Note that \texttt{<name>} is case\hyp insensitive and may not contain spaces.
Special characters are allowed if \TeX{} can cope with them (i.e., no comment signs, no unbalanced braces, no backslashes...).
\item They create a style \style{/yquant/operators/every <name>} and assign the optional \texttt{<style>} to it.
- If no style is provided, the default style will inherit from \style{/yquant/operators/every box}.
+ If no style is provided, the default style will inherit from \style{/yquant/operators/every rectangular box}\compat{Changed in 0.6}.
+ If a \texttt{compat} version before \texttt{0.6} is chosen, \style{/yquant/operators/every box} will instead be the ancestor.
\item They define \texttt{<content>} to be the value that is written into the box.
This \texttt{<content>} is expanded in a protected manner at the time of gate declaration.
You may need to prefix fragile macros by \tex!\protect!.
@@ -691,6 +694,12 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
\end{itemize}
\end{option}
+ \begin{option}[New in 0.6]{register/default lazy name}!!
+ The printed name that is used by default if a new register is created implicitly (i.e., without using any of \gate{qubit}, \gate{cbit}, \gate{qubits}, or \gate{nobit}, but inside a \texttt{yquant*} environment by just using the register).
+ The same macros as with \style{/yquant/register/default name} are available.
+ Note that this default setting is not used when the register is created via an \gate{init} gate---its value always overwrites the default.
+ \end{option}
+
\begin{option}[Changed in 0.4]{every label}!shape=yquant-init, anchor=center, align=right, outer xsep=2pt, /yquant/operator/if multi={draw, decoration={gapped brace, mirror, raise=2pt}, decorate}!
This style is installed for every single register name label (i.e., upon creation and when used with the \gate{init} gate).
The default style allows to use line breaks in the labels.
@@ -877,8 +886,10 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
Note that the \texttt{shorten} keys are only present in the default style if you specify at least the compatibility version \texttt{0.4}.
\end{option}
- \begin{option}{operators/every box}!shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm!
+ \begin{option}[Changed in 0.6]{operators/every box}!/yquant/operators/every rectangular box!
This style is installed for every \gate{box} operator.
+ Note that with a \texttt{compat} setting strictly smaller than~\texttt{0.6}, the definition of this style was the one that is now \style{/yquant/operators/every rectangular box}, and this style was also the base style from which all box\hyp like gates inherited.
+ With a \texttt{compat} setting of at least~\texttt{0.6}, no other gates apart from \gate{box} will use this style directly or indirectly.
\end{option}
\begin{option}[Changed in 0.4\\New in 0.2]{operators/every custom gate}!/yquant/operators/subcircuit/seamless!
@@ -893,7 +904,7 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
The \texttt{yquant-dmeter} shape consists of a rectangle whose right side is replaced by a circle, resembling the letter ``D.''
\end{option}
- \begin{option}{operators/every h}!/yquant/operators/every box!
+ \begin{option}{operators/every h}!/yquant/operators/every rectangular box!
This style is installed for every \gate{h} (Hadamard) operator.
\end{option}
@@ -918,7 +929,7 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
The \texttt{yquant-oplus} shape resembles the addition\hyp modulo\hyp two symbol $\oplus$.
\end{option}
- \begin{option}{operators/every pauli}!/yquant/operators/every box!
+ \begin{option}{operators/every pauli}!/yquant/operators/every rectangular box!
This style is installed for every Pauli operator, i.e., \gate{x}, \gate{y}, and \gate{z}.
\end{option}
@@ -926,6 +937,11 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
This style is installed for every \gate{phase} gate $\ketbra00 + \ee^{\ii\phi} \ketbra11$.
\end{option}
+ \begin{option}[New in 0.6]{operators/every rectangular box}!shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm!
+ This style is not associated to any particular gate, but will be inherited by a lot of gates that have a rectangular box frame with some text.
+ This style should not be used with a \texttt{compat} setting strictly smaller than~\texttt{0.6}.
+ \end{option}
+
\begin{option}{operators/every slash}!shape=yquant-slash, x radius=.5mm, y radius=.7mm, draw!
This style is installed for every \gate{slash} pseudo\hyp gate, i.e., the one that is used to indicate that a single register line actually denotes multiple registers.
\end{option}
@@ -1004,6 +1020,10 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
The \texttt{yquant-swap} shape consists of a single cross.
\end{option}
+ \begin{option}[New in 0.6]{operators/every text}!shape=yquant-rectangle, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm!
+ This style is installed for every \gate{text} gate.
+ \end{option}
+
\begin{option}[New in 0.1.2]{operators/every wave}!shape=yquant-circle, radius=.5mm, fill!
This style is installed for every \gate{correlate} gate.
\end{option}
@@ -1054,10 +1074,10 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
For nested subcircuits, you will get multiple prefixes.
\compat{New in 0.5}The prefixing behavior can be influenced by \style{/yquant/operators/subcircuit/name mangling}.
- \subsection{Shapes and the drawing pipeline}
+ \subsection{Shapes and the drawing pipeline}\label{sec:pipeline}
All \Yquant{} shapes have the anchors available you would typically expect from a \TikZ{} shape of the given outline.
The \texttt{center} anchor will be aligned to the wire.
- \compat{Changed in 0.1.2}In addition to the normal paths implemented by \TikZ{} shapes, those fit for \Yquant{} must additionally implement clipping paths, a \Yquant{} addition to \TikZ{} shapes.
+ \compat{Changed in 0.1.2}In addition to the normal paths implemented by \TikZ{} shapes, the width and height of those fit for \Yquant{} at least twice as large as given by the \texttt{/tikz/x~radius} and \texttt{/tikz/y~radius}; and they must implement clipping paths, a \Yquant{} addition to \TikZ{} shapes.
Such a path has to provide the ``clipping outline,'' i.e., anything that should not contain register or control lines.
There may be a difference between horizontal and vertical clipping outlines.
To understand clipping paths, \Yquant's drawing pipeline needs to be explained.
@@ -1102,7 +1122,7 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
Hence, the additional extent stemming from them should \emph{not} be equally distributed among all registers, but either to the height of the first or the depth of the last one.
Currently, \Yquant{} is unable to detect this (and, considering the fact that you can place \texttt{label}s at any angle, this is not an easy problem to solve except for special cases).
\item If you make use of a discontiguous \gate{init} gate with a large vertical extent, \Yquant{} will correctly allocate space as if the gate's content were placed in the vertical center.
- However, if there is no way to put the arch of the brace at the middle, as the register at this position is excluded from the gate, the content will be shifted---but only after calculating the extent.
+ However, if there is no way to put the arch of the brace at the middle, as the register at this position is excluded from the gate, the content will be shifted---but only \emph{after} calculating the extent.
Hence, the automatically calculated vertical positions will be unsuitable.
\end{itemize}
\item Sometimes, there is more space available than \Yquant{} thinks because you already discarded some wire.
@@ -1130,6 +1150,7 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
This section lists all operations \Yquant{} currently understands.
It also details all arguments that can be given to customize the operation, apart from \texttt{name} and \compat{New in 0.4}\texttt{overlay}, which are always available.
Note that the \tex![value=<value>]! attribute can (and should) alternatively be given as a braced expression that follows the name of the register.
+ Within \tex!<value>!, unless specified differently, the macro \tex!\idx! is always available and corresponds to the index of the current register in the list of targets.
\subsection[\texorpdfstring{\yquant!addstyle!}{addstyle}]{\compat{New in 0.1.2}\yquant!addstyle!}\label{gate:addstyle}
Syntax: \yquant!setstyle <target>;! \\
@@ -1182,6 +1203,7 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
Syntax: \yquant!correlate <target>;! \\
This is a pseudo\hyp gate that indicates a correlation (usually a Bell\hyp state) present between the multi\hyp registers involved.
This gate should span multiple registers and does not allow for controls.
+ The style \style{/yquant/operators/every wave} is installed.
\emph{Possible attributes:} none
@@ -1252,22 +1274,20 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
The style \texttt{/yquant/every <type> label} is installed additionally.
\item \yquant![value=<value>]! (required) \\
Denotes the label that is printed to the left of the wire.
-
- Inside the value, \tex!\idx! expands to the current index within the register list.
\end{itemize}
\subsection[\texorpdfstring{\yquant!inspect!}{inspect}]{\compat{New in 0.4}\yquant!inspect!}\label{gate:inspect}
Syntax: \yquant!inspect <target>;! \\
This is a pseudo\hyp gate that allows to print the current state of one or multiple registers within a circuit.
It may span multiple registers, but does not allow for controls.
- The style \style{/yquant/every inspect} is installed.
- Essentially, it is the same as an \gate{output} gate that will be drawn immediately at the current position and not deferred until the end.
+ The style \style{/yquant/operators/every inspect} is installed.
+ Essentially, it is the same as an \gate{output} gate that will be drawn immediately at the current position and not deferred until the end; hence, it also draws braces when used in a multi\hyp register context.
+ \compat{New in 0.6}If this is not desired, use the \gate{text} gate instead.
\emph{Possible attributes:}
\begin{itemize}
\item \yquant![value=<value>]! (required) \\
Denotes the text that is to be printed.
- Inside the value, \tex!\idx! expands to the current index within the register list.
\end{itemize}
\subsection[\texorpdfstring{\yquant!measure!}{measure}]{\compat{Changed in 0.4}\yquant!measure!}\label{gate:measure}
@@ -1320,12 +1340,12 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
It may only be specified once per register.
It may span multiple registers, but does not allow for controls.
The style \style{/yquant/every output} is installed, and also the style \texttt{/yquant/every <type> output}, where \texttt{<type>} is the type of the affected register (at the time of printout).
+ \compat{New in 0.6}Note that while outputs can be named, the name will only become available after the \texttt{yquant} environment itself was ended (but of course before the outer \texttt{tikzpicture} was closed).
\emph{Possible attributes:}
\begin{itemize}
\item \yquant![value=<value>]! (required) \\
Denotes the text that is to be printed.
- Inside the value, \tex!\idx! expands to the current index within the register list.
\end{itemize}
\subsection{\texorpdfstring{\yquant!phase!}{phase}}\label{gate:phase}
@@ -1411,12 +1431,15 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
This gate is only available if a compatibility version before \texttt{0.4} is chosen.
- \subsection{\texorpdfstring{\yquant!slash!}{slash}}\label{gate:slash}
+ \subsection[\texorpdfstring{\yquant!slash!}{slash}]{\compat{Changed in 0.4}\yquant!slash!}\label{gate:slash}
Syntax: \yquant!slash <target>;! \\
This is a pseudo\hyp gate used to denote that a single line actually represents multiple registers.
It is drawn as a short slash through the line of the register.
- Note that this gate, in contrast to all others, is positioned on the line extending from the last gate or the initialization line of the registers and does not advance the register's horizontal position.
The style \style{/yquant/operators/every slash} is installed.
+ Note that this gate will ignore the \style{/yquant/operator/minimum width} key.
+ With a \texttt{compat} key of~0.3 or earlier, the gate was special in that it did not advance the horizontal position on the wire, which allows to use it on only some of the wires without leading to a ragged start of subsequent gates.
+ However, as \Yquant's default separation is not large enough to give a pleasant layout when the slash is squeezed in the initial separation, this was dropped as of version~0.4.
+ Use the \gate{align} gate after all \gate{slash}es to get a better layout.
\emph{Possible attributes:} none
@@ -1468,6 +1491,20 @@ IndexSingle = ?number? | ( [ ?number? ], "-", [ ?number? ] );
\emph{Possible attributes:} none
+ \subsection[\texorpdfstring{\yquant!text!}{text}]{\compat{New in 0.6}\yquant!text!}\label{gate:text}
+ Syntax: \yquant!text <targets> | <pcontrol> ~ <ncontrol>;! \\
+ This is a pseudo\hyp gate that allows to write some text within the circuit.
+ It may span multiple registers and allows for controls (though the situations in which controls make sense are pretty scarce).
+ The style \style{/yquant/operators/every text} is installed.
+ Contrary to the \gate{inspect} gate, this gate will not draw curly braces in multi\hyp register use.
+ It basically corresponds to a \gate{box} gate with suppressed drawing.
+
+ \emph{Possible attributes:}
+ \begin{itemize}
+ \item \yquant![value=<value>]! (required) \\
+ Denotes the text that is to be printed.
+ \end{itemize}
+
\subsection{\texorpdfstring{\yquant!x!}{x}}\label{gate:x}
Syntax: \yquant!x <target> | <pcontrol> ~ <ncontrol>;! \\
This is a Pauli $\sigma_{\symup x}$ gate $\ketbra01 + \ketbra10$, denoted by a rectangle that contains the letter $X$.
@@ -1899,7 +1936,7 @@ qubit {$\ket{q_{\idx}} = \Ifcase\idx\relax \ket\psi \Else \ket0 \Fi$} q[3];
\yquantset{operator/separation=2mm}
For a better orientation, we use the same section headings as the \pkg{qcircuit} manual.
The manual uses unnamed registers a lot; often, we will use the \tex!yquant*! environment to make things more concise.
- As the \pkg{qcircuit} manual uses a bit larger separation between the operators than \Yquant's default, we globally say\\*\tex!\yquantset{operator/separation=1em}!.
+ As the \pkg{qcircuit} manual uses a bit larger separation between the operators than \Yquant's default, we globally say\\*\tex!\yquantset{operator/separation=2mm}!.
\subsubsection{I. Introduction}
\begin{example}<Updated in 0.5, 0.4, 0.1.1>%
@@ -2289,21 +2326,20 @@ qubit {$\ket{q_{\idx}} = \Ifcase\idx\relax \ket\psi \Else \ket0 \Fi$} q[3];
\clearpage
\paragraph{C. Non-gate inserts, forcing space, and swap}\leavevmode
- \begin{example}<Updated in 0.1.1>
+ \begin{example}<Updated in 0.6, 0.1.1>
\begin{codeexample}
\begin{tikzpicture}
\begin{yquant*}
[name=sw]
swap (a[0-1]);
- [draw=none]
- box {$X$} a[1];
+ text {$X$} a[1];
slash b;
box {$H^{\otimes n}$} b;
\node[anchor=199] at (sw-0.north) {Defective Circuit};
\end{yquant*}
\end{tikzpicture}
\end{codeexample}
- Here, the intermediate text was inserted by using a \gate{box} without drawing.
+ Here, the intermediate text was inserted by using a \gate{text} gate; before version~0.6, this would have to be done by a \gate{box} gate with \yquant![draw=none]! attribute.
Another way would be to use an \gate{init} command, although this is semantically wrong (probably).
\end{example}
@@ -2382,19 +2418,19 @@ qubit {$\ket{q_{\idx}} = \Ifcase\idx\relax \ket\psi \Else \ket0 \Fi$} q[3];
\end{example}
\paragraph{B. Labeling}\leavevmode
- \begin{example}<Updated in 0.4>
+ \begin{example}<Updated in 0.6, 0.4>
\begin{codeexample}
\begin{tikzpicture}
- \begin{yquant}[every initial label/.style={anchor=south east, yshift=1mm}, every post measurement control=direct, operators/every box/.append style={draw=none}]
+ \begin{yquant}[every initial label/.style={anchor=south east, yshift=1mm}, every post measurement control=direct]
qubit {\rlap{\hskip2mm $a$}} a;
qubit {\rlap{\hskip2mm $b$}} b;
nobit out;
hspace {5mm} -;
measure b;
- box {$B$} out | b;
+ text {$B$} out | b;
measure a;
- box {$A$} out | a;
+ text {$A$} out | a;
discard -;
\end{yquant}
\end{tikzpicture}
@@ -2402,10 +2438,10 @@ qubit {$\ket{q_{\idx}} = \Ifcase\idx\relax \ket\psi \Else \ket0 \Fi$} q[3];
We support measurements with vertical outputs, but only if they replace the positive control of some action.
Here, we fake this behavior by introducing an invisible register at the bottom, which will contain the outputs.
In order to disable the line around the \gate{box}es, we used the \style{/yquant/operators/every box} style, which here was most convenient, as the only \gate{box}es in use are those without an outline.
- However, if we instead want to say \texttt{[draw=none]} as an attribute to the \gate{box}es, this will also remove the outline of the measurements.
- The reason for this is that giving this as an attribute will in fact populate \style{/yquant/operator style}; and internally, the measurement will be nested within the same scope that draws the \gate{box}---so the options given to the \gate{box} will be inherited by the \gate{measure}ment.
+ Note that if we were to give style options to the \gate{text}s, they would also affect the measurements.
+ The reason for this is that internally, the measurement will be nested within the same scope that draws the \gate{text}---so the options given to the \gate{text} will be inherited by the \gate{measure}ment.
As an operator style overwrites default styles, this will also apply to the measurements.
- Hence, to circumvent this, we would have to additionally say \texttt{[draw]} as an attribute to the \gate{measure}ments, although this is already included in their native style.
+ Hence, to circumvent this, we would need to \emph{revert} the options as attributes to the \gate{measure}ments, even if the reverted option was already included in their native style.
Repositioning the initial labels needs some care and manual fine\hyp tuning.
\end{example}
@@ -2434,6 +2470,7 @@ qubit {$\ket{q_{\idx}} = \Ifcase\idx\relax \ket\psi \Else \ket0 \Fi$} q[3];
\end{codeexample*}
Note that \tex!\begin{yquant*}! must not be followed by a line break (unless masked by \tex!%!) if options follow.
Also note that here, we cannot make use of a subcircuit due to the very last control, which would then control an inner gate of said subcircuit---but they are not exposed.
+ \iffalse\end{yquant*}\fi% code folding
\end{example}
\endgroup
@@ -2487,15 +2524,14 @@ qubit {$\ket{q_{\idx}} = \Ifcase\idx\relax \ket\psi \Else \ket0 \Fi$} q[3];
\end{example}
\paragraph{B. Wires and arrows}\leavevmode
- \begin{example}<Updated in 0.1.2>
+ \begin{example}<Updated in 0.6, 0.1.2>
\begin{codeexample*}
% \usetikzlibrary{quotes}
\begin{tikzpicture}
\begin{yquant}[operator/separation=1cm, every label/.append style={align=center}]
qubit {$\ket0$\\initial state} a;
- [draw=none]
- box {$X$} a;
+ text {$X$} a;
["$0$/$1$", type=qubit]
measure a;
@@ -3100,9 +3136,11 @@ $=$
\end{yquant*}
\end{tikzpicture}
\end{codeexample}
+ Note that assigning styles in this way will forward them to \style{/yquant/operator style}, i.e., if you have controls, the style will not apply to them.
+ \style{/yquant/style} is suitable to style both, e.g., \tex|[style={fill=red!20}]|.
\end{example}
- \begin{example}<Updated in 0.4>
+ \begin{example}<Updated in 0.6, 0.4>
\begin{codeexample*}
% \usetikzlibrary{shapes.symbols, fit}
\begin{tikzpicture}
@@ -3114,8 +3152,8 @@ $=$
cnot anc1 | data;
[after=data]
qubit {$\ket0$} anc2[2];
- [name=box, draw=none]
- box {\phantom{noise}} (data, anc1);
+ [name=noise]
+ text {\phantom{noise}} (data, anc1);
cnot anc2[0] | data;
cnot anc2 | anc1[0];
cnot anc2[1] | anc1[1];
@@ -3123,7 +3161,7 @@ $=$
[blue] measure anc2[1];
\end{yquant}
\node[starburst, cyan, fill=yellow, draw=red, line width=2pt,
- inner xsep=-4pt, inner ysep=-5pt, fit=(box)] {noise};
+ inner xsep=-4pt, inner ysep=-5pt, fit=(noise)] {noise};
\end{tikzpicture}
\end{codeexample*}
\TikZ{} shapes cannot simply be used with \Yquant.
@@ -3206,7 +3244,7 @@ $=$
\clearpage
\subsubsection{VIII. Otherwise undocumented features}
- \begin{example}<Updated in 0.4>
+ \begin{example}<Updated in 0.6, 0.4>
\begin{codeexample*}
% \usetikzlibrary{quantikz,fit}
\begin{tikzpicture}
@@ -3219,8 +3257,7 @@ $=$
h a, b;
box {$U$} c | a;
- [draw=none]
- box {$\dots$} a, b-;
+ text {$\dots$} a, b-;
box {$U^k$} c | b;
h a, b;
\end{yquant}
@@ -3254,6 +3291,1441 @@ $=$
\end{example}
\endgroup
+ \subsection[\texorpdfstring{\pkg{qpic}}{qpic} documentation]{\compat{Added in 0.6}\pkg{qpic} documentation}
+ \begingroup
+ \yquantset{operator/separation=3mm, register/default name=$\reg$, register/default lazy name=$\reg$}%
+ Again, our section headings will be the same as in the \pkg{qpic} manual.
+ As the \pkg{qpic} manual uses a bit larger separation between the operators than \Yquant's default, we globally say \tex!\yquantset{operator/separation=3mm, register/default name=$\reg$, register/default lazy name=$\reg$}!, which allows to easily generate all the registers on\hyp the\hyp fly.
+
+ \subsubsection{1 Introduction}
+ \begingroup%
+ \mdfapptodefinestyle{bdBox}{%
+ leftmargin=-.12\linewidth,
+ rightmargin=-.12\linewidth
+ }%
+ \begin{example}\label{ex:qupicfirst}
+ \begin{codeexample*}
+\def\reversecircuit#1{%
+ \begin{tikzpicture}
+ \let\high=\empty
+ \listeadd\high{#1}
+ \def\cnot##1|##2;{%
+ \ifinlist{##2}\high{
+ \yquant [style=red] cnot a[##1] | a[##2];
+ \ifinlist{##1}\high{
+ \listremove\high{##1}
+ \yquant addstyle {black} a[##1];
+ }{
+ \listadd\high{##1}
+ \yquant addstyle {red} a[##1];
+ }
+ }{
+ \yquant cnot a[##1] | a[##2];
+ }
+ }
+ \def\cnotA{\cnot 0|1; \cnot 2|3; \cnot 4|5; \cnot 6|7;}
+ \def\cnotB{\cnot 2|1; \cnot 4|3; \cnot 6|5; \cnot 8|7;}
+ \def\cnotC{\cnot 1|0; \cnot 3|2; \cnot 5|4; \cnot 7|6;}
+ \def\cnotD{\cnot 1|2; \cnot 3|4; \cnot 5|6; \cnot 7|8;}
+ \def\cnotBlock{\cnotA \cnotB barrier (-); \cnotC \cnotD}
+ \begin{yquant}[operator/minimum width=0pt, register/minimum height=2mm,
+ register/minimum depth=2mm]
+ qubit {\Ifnum\idx=#1\color{red}\Fi$\reg_{\The\numexpr\idx+1}$} a[9];
+ addstyle {very thick, red} a[#1];
+
+ \cnotBlock barrier (-);
+ \cnotBlock barrier (-);
+ \cnotBlock barrier (-);
+ \cnotBlock barrier (-);
+ \cnotBlock
+ output {\protect\xifinlist{\idx}{\high}{\color{red}}\relax
+ $a_{\The\numexpr9-\idx}$} -;
+ \end{yquant}
+ \end{tikzpicture}%
+}
+\reversecircuit2
+ \end{codeexample*}
+ This is an extremely interesting example, which could have been implemented in a lot of different manners.
+ We chose an approach where we deferred the logic of coloring the gates entirely to \TeX.
+ Note that we put everything, including the whole \texttt{tikzpicture} itself, in a macro \tex!\reversecircuit!, which we call directly after its definition by saying \tex!\reversecircuit2!.
+ This is of course an overkill in this situation---there is no need for the macro definition.
+ However, note that the macro expects the wire that is to be colored in red as its argument.
+ So by slightly changing the invocation to
+ \begin{minted}{tex}
+\foreach \ici in {0, ..., 8} {
+ \reversecircuit\ici
+ \par\vspace{1cm}
+}
+ \end{minted}
+ we are able to render the circuit with all different initial wires one after the other very easily.
+ We do not show the output in the manual to keep it succinct, but just try it out by yourself.
+
+ We now explain what is done in the macro.
+
+ We first define an \pkg{etoolbox} list that is stored in \tex!\high!.
+ The idea is that this list holds at any point in time the indices of all the registers that are currently colored in red.
+ Initially, we add the index that was given as a parameter to the macro---in our case, this was \tex!2!.
+ Note we use \tex!\listeadd! instead of \tex!\listadd!, which is important for the invocation via \tex!\foreach!---we want to have the number in the list, not the macro \tex!\ici! that holds the index of the initially colored wire).
+
+ Next, we do not want to manually do the bookkeeping of this list.
+ All we want to do is to issue the command to put a \gate{cnot} gate on the appropriate registers and \TeX{} should keep track of the correct coloring and register state.
+ For this, we first define a macro \tex!\cnot! that expects the index of the target and the index of the control register.
+ Within this macro, we check whether the register of the control is currently highlighted (\tex!\ifinlist{#2}\high!).
+ If this is not the case, we draw the \gate{cnot} gate without any additional styles (note that since we interrupted the \Yquant{} parser due to the lots of intervening macros, we first have to restart it saying \tex!\yquant!).
+ However, if it is the case that the control register is currently highlighted, we draw the \gate{cnot} gate with the attribute \texttt{[style=red]}---we do not only want to draw the gate itself in red (for which \texttt{[red]} would be sufficient), but also its control line and the control blob, so we use the \style{/yquant/style} shorthand.
+ Note that in the \pkg{qpic} manual, some of the control lines are thicker than others.
+ This could be implemented by adding the argument \tex!every control line/.append style={very thick}!; however, as it is unclear what the thick line should indicate, we did not add this to the example.
+
+ Then, we have to change the state of the target register appropriately, since the highlighting state will propagate from control to target.
+ If the target register was already highlighted, we have to remove it from the list and we change its line color back to \texttt{black}; if it was not highlighted, we add it to the list and change its line color to \texttt{red}.
+ Note that the use of \gate{addstyle} will keep adding styles, so in the end, the register line style will be a long string \texttt{red,black,red,black,...}; we could do better by saying \gate{setstyle}, which would overwrite the line style.
+ However, since we will initially set the line width of \tex!a[#1]! to \texttt{very thick}---which should be kept throughout the circuit---we would have to take additional care not to lose this setting.
+ Here, we chose the simpler version.
+
+ After setting the coloring preliminaries, we note that if we slice the circuit at any time, it will have four possible gate configurations (or a \gate{barrier}).
+ We define abbreviations for these in the macros \tex!\cnotA! to \tex!\cnotD!.
+ Since they will always follow in this order, we also define a \tex!\cnotBlock! abbreviation that executes these configurations together with their intermediate \gate{barrier}.
+ We do not include the final barrier, since it is not present in the last block.
+
+ Now, we start the \texttt{yquant} environment.
+ We give some options for a nicer spacing and initialize the registers.
+ In the \pkg{qpic} example, the registers are $1$\hyp indexed, so we use \tex!\The\numexpr\idx+1! to give back the value of the current register index (\tex!\idx!) plus one; we also conditionally color the register name in red if the index coincides with the parameter.
+ Note that here we use \Yquant's shorthand for \tex!\protect\the!, \tex!\protect\ifnum!, and \tex!\protect\fi!, which are \tex!\The!, \tex!\Ifnum!, and \tex!\Fi!, to get the correct expansion behavior.
+
+ Then, we add the initial style for the \tex!a[#1]! wire.
+ Inserting the gates together with the correct coloring is now extremely simple: we just need to call our \tex!\cnotBlock! command and intersperse it with \gate{barrier}s.
+ At the end, we output all the gates in reverse order, which works similarly to the initialization of the gates, and also conditionally color the reversed register.
+ This coloring could in principle be done similarly to the coloring of the initial label, saying something like \tex!\Ifnum\numexpr8-\idx=#1 \color{red}\Fi!.
+ Here, we chose the ``more honest'' approach to color all the registers that are still present in the coloring list---note the need to \tex!\protect! the \pkg{etoolbox} macro \tex!\xifinlist!.
+ In this way, we could, e.g., terminate the circuit earlier and still get the correct output coloring at this particular point.
+
+ Note that if there were more that just five blocks, we could also have made use of \TikZ's \tex!\foreach! loop to output all the \tex!\cnotBlock! commands.
+ However, be aware of the fact that \tex!\foreach! puts its content in a group, so the \tex!\high! list assignments would have been local and forgotten in the next iteration.
+ Either they would need to be made globally or some non\hyp grouping loop construct would have to be used (e.g., \tex!\pgfplotsforeachungrouped!).
+ \end{example}
+ \endgroup
+
+ \clearpage
+ \subsubsection{2 Simple Examples}
+ \paragraph{2.1 Example 1: Majority}\leavevmode
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \begin{yquant*}
+ box {\rotatebox{90}{$\operatorname{MAJ}$}} (a, b, c);
+
+ text {$=$} (-);
+
+ cnot b | c;
+ cnot a | c;
+ cnot c | a, b;
+
+ output {$a \oplus c$} a;
+ output {$b \oplus c$} b;
+ output {$\operatorname{MAJ}(a, b, c)$} c;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample*}
+ \end{example}
+
+ \clearpage
+ \paragraph{2.2 Example 2: Quantum Fourier Transform}\leavevmode
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \begin{yquant}[operators/every box/.append style={shape=yquant-circle, radius=2.5mm}]
+ qubit {$x_2$} x2;
+ qubit {$x_1$} x1;
+ qubit {$x_0$} x0;
+
+ h x2;
+ box {$2$} x2 | x1;
+ box {$3$} x2 | x0;
+ h x1;
+ box {$2$} x1 | x0;
+ h x0;
+
+ output {$\frac{1}{\sqrt2} (\ket0 + e^{2\pi i \cdot 0.x_2 x_1 x_0}) \ket1$} x2;
+ output {$\frac{1}{\sqrt2} (\ket0 + e^{2\pi i \cdot 0.x_1 x_0}) \ket1$} x1;
+ output {$\frac{1}{\sqrt2} (\ket0 + e^{2\pi i \cdot 0.x_0}) \ket1$} x0;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample*}
+ In this example, we opted to use three distinct registers instead of one vector register, since the reversed indexing would probably have led to more confusion.
+ We globally overwrite the \style{/yquant/operators/every box} style to use a circular shape instead.
+ Note that this would usually be an ellipse, so we explicitly set the radius to a value that exceeds the minimum (half) width.
+ As of version~0.6, the style \style{/yquant/operators/every box} is no longer the base style for other rectangular boxes such as \gate{h} (note this requires a compatibility version of at least \texttt{0.6} or higher).
+ For earlier versions, the change in shape would also affect the Hadamard gate and therefore would have to be reverted using the \style{/yquant/operators/every h} style.
+ \end{example}
+
+ \clearpage
+ \paragraph{2.3 Example 3: Shor's Algorithm}\leavevmode
+ \begingroup%
+ \mdfapptodefinestyle{bdBox}{%
+ leftmargin=-.12\linewidth,
+ rightmargin=-.12\linewidth
+ }%
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}[rotate=-90, yscale=-1, every node/.append style={rotate=90, xscale=-1}]
+ \def\explain#1#2{%
+ \yquant
+ [anchor=east] text {#1} explainLeft;
+ [anchor=west] text {$\displaystyle#2$} explainRight;
+ align -;
+ }
+ \begin{yquant}[every initial label/.style={anchor=south},
+ every output/.style={anchor=north},
+ every control/.append style={radius=1.5mm},
+ operators/every slash/.append style={x radius=3mm, y radius=1.5mm},
+ operators/every box/.append style={y radius=4mm},
+ operators/every measure/.append style={y radius=4mm},
+ operator/minimum width=1.32cm]
+ nobit explainLeft;
+ qubit {$\ket{0\dotsm0}$} x; slash x;
+ qubit {$\ket{0\dotsm0}$} y; slash y;
+ nobit explainRight;
+ align -;
+
+ box {$H^{\otimes n}$} x;
+ \explain{Quantum Hadamard Transform}
+ {\sum_{x = 0}^{2^n -1} \ket x \ket 0}
+
+ box {$a^x \bmod N$} y | x;
+ \explain{Exponentiation}
+ {\sum_{x = 0}^{2^n -1} \ket x \ket{a^x \bmod N}}
+
+ measure y; output {$y$} y;
+ \explain{Measure $y = a^b$}
+ {\sum_{j = 0}^{\lfloor\frac{2^n -1}{r}\rfloor} \ket{b + j r} [y]}
+
+ box {QFT} x;
+ \explain{Quantum Fourier Transform}
+ {\sum_{x = 0}^{2^n -1} \left( \sum_{j = 0}^{\lfloor\frac{2^n -1}{r}\rfloor}
+ \omega^{x * (b + j r)} \right) \ket x}
+
+ output {$?$} x;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample*}
+ Once again, this is a very interesting example.
+ \Yquant{} does not support a vertical circuit layout \emph{officially}.
+ However, \Yquant{} is built on top of \TikZ, so we can certainly try to emulate a vertical layout by means of rotations.
+ First of all, we rotate the whole \texttt{tikzpicture}, saying \tex!rotate=-90!, so that the circuit grows downwards.
+ While this is very straightforward, it leads to two immediate problems:
+ \begin{itemize}
+ \item The registers were declared in top\hyp to\hyp bottom order; if we rotate everything, this becomes a right\hyp to\hyp left order.
+ In order to change this to a left\hyp to\hyp right order, we must mirror every horizontal coordinate; due to the rotation, this corresponds to \tex!yscale=-1! (not \tex!xscale!).
+ \item The gates themselves should not be rotated.
+ In fact, no text should be rotated.
+ However, as by default, the \style{/yquant/every circuit} style will install the \texttt{transform shape} option to every node as of version~0.4, the nodes will also be rotated.
+ The first idea to disable \texttt{transform shape} does not turn out to work well, as the spacings are somehow messed up.
+ Instead, we just undo the rotation and scaling (note that now we need \tex!xscale=-1!, as after the reverse rotation, we are back to the ``proper'' coordinate system).
+ \end{itemize}
+ Then, there are some minor issues regarding the anchors of initial labels and output.
+ The default settings for them, \texttt{east} and \texttt{west} are of course inappropriate in a rotated layout, so those must be changed.
+ All the rest of the options that are given to the \texttt{yquant} environment just serve to match the appearance given in the \pkg{qpic} manual: we enlarge the \gate{slash}, the \gate{box}es and the \gate{measure}ments, and we also increase the global value of \style{/yquant/operator/minimum width}.
+ Remember that this is the minimum ``width'' (in the rotated scenario, it becomes a height) that \Yquant{} reserves for every single operator (unless it is larger), and it will center the operator within an invisible rectangle of this width if it is smaller.
+ So by matching this value to the largest height that occurs in the explanations in the circuit, we achieve an approximate vertical centering.
+
+ Finally, there is some repetitive structure within the circuit, which we defer to a custom macro \tex!\explain!: We always want to draw a \gate{text} gate in our first invisible register \yquant!explainLeft!; however, this should not be centered, but rather aligned to the right, so we give the proper \tex!anchor=east!.
+ We also need the same thing on the right, just mirrored and with a \tex!\displaystyle! math environment; and after all the explanations are done, we \gate{align} all registers (if the minimum width/height was chosen to be exactly larger or equal to the actual height of every gate, this would not be necessary; but with two decimals, this is probably not precisely the case).
+
+ Note that the code example above would work exactly in this way in traditional \LaTeX{} documents; however, this document is set with \pkg{unicode-math}.
+ This leads to a problem when using \tex!\bmod!, which has to be \tex!\protect!ed---or, as we did here, just say \tex!\robustify\bmod! somewhere before its usage and after loading all the packages.
+ \end{example}
+ \endgroup
+
+ \clearpage
+ \paragraph{2.4 Example 4: Teleportation}
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}[rotate=-90, yscale=-1, every node/.append style={rotate=90, xscale=-1}]
+ \begin{yquant}[every initial label/.style={anchor=south},
+ every output/.style={anchor=north},
+ operators/every barrier/.append style={rotate=-90}]
+ nobit explainLeft;
+ qubit {\color{red}$\ket\phi$} q;
+ qubit {$\ket0$} q[+2];
+ nobit explainRight;
+ setstyle {red} q[0];
+
+ h q[1];
+ cnot q[2] | q[1];
+ setstyle {red} q[1];
+ setstyle {blue} q[2];
+ [y radius=5mm, anchor=west]
+ inspect {Alice and Bob form an\\entangled pair of qubits} (explainRight);
+ [operator/separation=0pt]
+ barrier (q);
+ align -;
+
+ [style=red, operator/separation=0pt] cnot q[1] | q[0];
+ [red] h q[0];
+ [red] measure q[0, 1];
+ [red, y radius=9mm, anchor=east, align=right, shape=yquant-init, decoration={mirror}]
+ inspect {Alice entangles\\and measures} (explainLeft);
+ align -;
+
+ [style=blue] x q[2] | q[1];
+ [style=blue] z q[2] | q[0];
+ discard q[0, 1];
+ [blue, y radius=5.5mm, anchor=west]
+ inspect {Bob applies gates based on\\Alice's measurements} (explainRight);
+
+ output {\color{blue}$\ket\phi$} q[2];
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample*}
+ Again, we ignore that it is not possible to render the circuit in this way and do it anyway.
+ The structure is similar to what we previously did.
+ For some reason, the \gate{barrier} shape is not content with the back\hyp rotation and we must again rotate it.
+
+ We now use \gate{inspect} gates to mimic the state information.
+ This gate will automatically draw curly braces as soon as it encounters a multi\hyp register use; hence, despite the fact that \yquant!explainRight! and \yquant!explainLeft! are single registers, we use them in a multi\hyp register fashion.
+ Next, the brace would only be high enough to incorporate the text (since it knows nothing about what goes on in the rest of the circuit); hence, we manually give it a \texttt{y radius} value that has to be determined appropriately.
+
+ Since the default operator separation before and after the \gate{barrier} look a bit large, we set them to zero (\style{/yquant/operator/separation} will always affect the distance of the current operator to the previous one, so we need this for the \gate{barrier} and for the first \gate{cnot} gate after the \gate{barrier}).
+
+ The \gate{inspect} gate on the left\hyp hand side needs some special attention.
+ In a horizontal layout, the brace will of course always be drawn left to the text, as the \gate{inspect} gate is supposed to denote the current state of the registers.
+ Therefore, we need to mirror the brace itself (\tex!decoration={mirror}!), and we also need to put it to the right\hyp hand side.
+ Coincidentally, the \texttt{yquant-init} style has the brace at its right\hyp hand side, so we just choose to change the style.
+ Using the \gate{init} gate instead would directly have invoked the correct \texttt{shape}; however, semantically, it is wrong, it would have changed the wire type to something visible (requiring a \gate{discard} directly afterwards) and it is also not scalable via \texttt{y radius}.
+ \end{example}
+
+ \subsubsection{3.1 Wires}
+ \paragraph{3.1.1 Wire Declarations}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a;
+ qubit b;
+ qubit {} c;
+
+ hspace {1cm} -;
+
+ output {$\phi$} a;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\makeatletter
+% https://tex.stackexchange.com/a/112212/32357
+\DeclareRobustCommand\rvdots{%
+ \vbox{%
+ \baselineskip4\p@\lineskiplimit\z@%
+ \kern-\p@%
+ \hbox{.}\hbox{.}\hbox{.}%
+ }%
+}
+\begin{tikzpicture}
+ \begin{yquant}[every nobit output/.style={}, register/separation=3mm]
+ qubit {$x_1$} x;
+ qubit {$\rvdots$} x[+1]; discard x[1];
+ qubit {$x_n$} x[+1];
+
+ hspace {1cm} -;
+
+ output {$y_1$} x[0];
+ output {$\rvdots$} x[1];
+ output {$y_n$} x[2];
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ This is one of at least four possible implementations (note we \href{https://tex.stackexchange.com/a/112212/32357}{defined \tex!\rvdots!}, since the native \tex!\vdots! does not appear to be very well\hyp centered).
+ It declares the ``invisible'' register as part of the vector register \yquant!x!.
+ As a consequence, whenever the whole vector register is addressed in operations, the operation is also drawn on the invisible register.
+ For multi\hyp register gates, this may be desired (they just span the whole region), for single\hyp register gates, this is most certainly undesired.
+ Note that \Yquant{} does not allow to declare an \gate{output} gate for invisible registers---usually, this does not make sense.
+ However, this is not enforced as a hard constraint, but rather due to the fact that the style \style{/yquant/every nobit output} does not exist.
+ To prevent an error message, we just define this as an empty style.
+ Also note that, to get a proper vertical spacing, we decided to use the \style{/yquant/register/separation} key---which works well, as there are no other registers.
+ If there were others, it would be better to increase the height and depth of the invisible register.
+
+ Alternatively, we might declare the invisible register with a completely different name.
+ This would create a discontiguous vector register \yquant!x!, which is probably the better thing to do for single\hyp register gates.
+ However, \Yquant{} may now try to split multi\hyp register gates into contiguous slices---there could be arbitrary registers between discontiguous parts of a vector register, and they should of course not be targeted if they are not in the list of targets of a gate---but here, we would actually want to have this.
+
+ A third approach mixes \Yquant{} and \TikZ{} code.
+ We declare a vector register with size two, manually increase, say, the depth of the first register, and put a \tex!\node! at the appropriate position by naming the initial labels.
+ In this way, vector usage will never target the ``invisible'' line---since it does not exist; both single\hyp{} and multi\hyp register gates will work appropriately.
+ As a drawback, we need to decide whether we want to enlarge the depth of the first or the height of the second register (or both, splitting in half)---but what if some gates will actually be so large that they would provide enough of height or depth had we just chosen a different way of distribution the space?
+
+ In order to remediate this, a fourth way using only two registers would be to defer the drawing of the dots to a multi\hyp register \gate{text} gate which receives a \texttt{y~radius} that enforces an appropriate separation.
+ \Yquant{} will then automatically perfectly distribute the vertical extents among height and depth of the involved registers.
+ The drawback with this approach is of course that the dots will be drawn \emph{within} the circuit, not to the left.
+ There is an undocumented option that we can use to shift the gate to the left; but since this only works for initializers, we still need to draw the dots for the outputs manually.
+ A possible implementation could look as follows.
+
+ \begingroup%
+ \makeatletter%
+ \DeclareRobustCommand\rvdots{%
+ \vbox{%
+ \baselineskip4\p@\lineskiplimit\z@%
+ \kern-\p@%
+ \hbox{.}\hbox{.}\hbox{.}%
+ }%
+ }%
+ \begin{codeexample}
+% \rvdots definition from above
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit {$x_1$} x;
+ qubit {$x_n$} x[+1];
+ [internal/move label, anchor=east, y radius=8mm]
+ text {$\rvdots$} (x);
+
+ hspace {1cm} -;
+
+ [name=o1]
+ output {$y_1$} x[0];
+ [name=o2]
+ output {$y_n$} x[1];
+ \end{yquant}
+ \path (o1.south west) -- (o2.north west) node[midway, /yquant/every output] {$\rvdots$};
+\end{tikzpicture}
+ \end{codeexample}
+ \endgroup%
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [decorate=false, draw=none]
+ init {$A$} (q[0, 1]);
+ init {$\ket0^{\otimes3}$} (q[2-4]);
+
+ hspace {1cm} -;
+
+ output {$B$} (q[1, 2]);
+ output {$\ket0^{\otimes2}$} (q[3, 4]);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that here the $A$ is drawn without the curly braces.
+ There are two simple ways to achieve this: by setting \texttt{draw} to \texttt{none}, the curly brace is suppressed, but still the~$A$ would be drawn at the same position as if the brace were there.
+ We additionally set \texttt{decorate} to \texttt{false} to fully remove any reminiscence of the brace, so that the text is closest to the wires.
+ (Note that just removing the decoration without also removing the drawing would lead to a vertical line that connects all the affected wires---this is how the \texttt{yquant-init} shape looks like in an undecorated fashion.)
+ \end{example}
+
+ \subsubsection{3.2 Gates}
+ \paragraph{3.2.1 Controlled NOT and controlled $Z$}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ not a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[register/default lazy name=$\symbol{\numexpr`a+\idx}$]
+ cnot q[1] | q[0];
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Since in \Yquant's notation, \texttt{b} is mentioned before \texttt{a}, it would also be created as the first wire.
+ If we instead resort to vector registers, we can directly specify which position our registers should have.
+ Of course, for longer circuits, an explicit declaration is probably favorable.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[register/default lazy name=$\symbol{\numexpr`a+\idx}$]
+ cnot q[2] | q[-1];
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ not a;
+ zz (b, c);
+ cnot c | a ~ b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \paragraph{3.2.2 General Gates}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ box {\symbol{\numexpr`A+\idx}} a, b;
+ box {$\tau$} (-);
+ box {GATE} a | b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that the macro \tex!\idx! is available in any gate, and it gives the index of the current register within the target list.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[operators/every box/.append style={shape=yquant-circle}]
+ box {$\rho$} a;
+ box {$\rho$} b | a;
+ box {$\rho$} (-);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that the macro \tex!\idx! is available in any gate, and it gives the index of the current register within the target list.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}[rotate=-90]
+ \begin{yquant*}[every initial label/.style={anchor=east}]
+ box {\rotatebox{90}{$M$}} (c, b) | a;
+ box {\rotatebox{90}{GATE}} (-);
+ box {\rotatebox{90}{$M^{-1}$}} (c, b) | a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Remember that \Yquant{} doesn't really support vertical layout, so it is always a bit of an experiment to make this work.
+ Multi\hyp register gates don't work too well when trying to apply the back\hyp rotation trick of before.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [name=fs] box {\Ifnum\idx<1 $f^{-1}$\Else $f$\Fi} (a, b), (c, d);
+ [name=g] box {$g$} (b, c) | a;
+ [shape=yquant-circle, name=theta] box {$\theta$} d;
+ \end{yquant*}
+ \draw (fs-0) -- (fs-1) (g) -- (theta);
+\end{tikzpicture}
+ \end{codeexample}
+ By putting the two $f$\hyp boxes into a single gate, we ensured that \Yquant{} will center them with respect to each other.
+ \end{example}
+
+ \clearpage
+ \paragraph{3.2.3 Other predefined Gates}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ h a;
+ h x;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ z a, b;
+ zz (-);
+ z a | b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ zz (a, b), (c, d);
+ zz (b, c);
+ zz (-b), (c-);
+ zz (b, c);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ swap (a, b);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \begin{yquant*}[plusctrl/.style={/yquant/every control/.style={/yquant/operators/every not}, /yquant/every positive control/.style={}}]
+ [plusctrl] box {$f$} (a, b) | c;
+ [plusctrl, shape=yquant-circle] box {$\zeta$} c | d;
+ [plusctrl] box {$f$} (a, b) | c;
+ cnot b | a;
+ cnot c | d;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample*}
+ This very unorthodox\hyp looking style can be achieved by altering the control styles in such a way that it basically looks like a \gate{not} gate.
+ \end{example}
+
+ \subsubsection{3.3 Attributes}
+ \paragraph{Size Attributes}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [y radius=20pt] box {HIGH} (a, b);
+ [x radius=20pt] box {WIDE} (-);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that \texttt{LONG} and \texttt{BROAD} do not make sense, as \Yquant{} does not support vertical layout.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}[rotate=-90, yscale=-1, every node/.append style={yscale=-1}]
+ \begin{yquant*}[every initial label/.style={rotate=45, anchor=east, shift={(.15, .15)}}]
+ [x radius=20pt]
+ box {\rotatebox{90}{HIGH}} (a, b);
+ [y radius=20pt]
+ box {\rotatebox{90}{WIDE}} (a, b);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Again, trying to properly adjust the position of the initial labels is more trial\hyp and\hyp error than anything else, and very fragile with respect to changes in the circuit.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ [register/minimum depth=10pt]
+ qubit a;
+ qubit b;
+ [register/minimum height=1pt]
+ qubit c;
+
+ cnot c | a, b;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ Upon creation, the minimum register sizes can be passed on to \Yquant; note that the \style{/yquant/register/minimum height} extends from the wire line to the top of the space that is allocated for the wire, whereas the corresponding key \style{/yquant/register/minimum depth} extends from the wire line to the bottom.
+ Hence, the values given here are half of \pkg{qpic}'s.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [inner sep=0pt, radius=2.5pt]
+ box {} a | b;
+ [shape=yquant-circle, radius=10pt]
+ box {$g$} b | a;
+ cnot a | b;
+ [operator style={radius=7.5pt}, control style={radius=4pt}]
+ cnot a | b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ To mimick closely \pkg{qpic}'s manual, we used an empty \gate{box} instead of the \gate{xx} gate, which also is a rectangle.
+ Note that the shapes that accept text also have an inner separation, which would interfere with the \texttt{radius} setting.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [x radius=12.5pt]
+ box {$f$} a;
+ [radius=12.pt, shape=yquant-circle]
+ box {$f$} a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that when changing to the \texttt{yquant-circle} shape, this will become an ellipse if only one of the radii is modified.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit {\color{purple}$a$} a;
+ setstyle {purple} a;
+ qubit b;
+
+ [style=green!50!black]
+ cnot a | b;
+ setstyle {red} b;
+ [orange, control style=blue]
+ h a | b;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\yquantdefinebox{circle}[shape=yquant-circle, draw, inner sep=0pt, radius=2mm]{}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [fill=red!50!white] box {$f$} a | b;
+ [fill=blue, name=b] circle a;
+ [fill=green, name=g] circle b;
+ not a;
+ [fill=yellow] not b;
+ \end{yquant*}
+ \draw (b) -- (g);
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ setstyle {dotted} a;
+ setstyle {very thick} b;
+ [dashed, fill=yellow] box {$G$} (-);
+ cnot a | b;
+ setstyle {densely dotted} a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}[on/.style={red, very thick}]
+ \begin{yquant*}[on/.style={style=red, control style={very thick}}]
+ cnot a | b;
+ qubit {\color{red}$c$} c;
+ setstyle {on} c;
+ [on] cnot b | c;
+ setstyle {on} b;
+ [on] cnot a | b;
+ setstyle {on} a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ This example demonstrates for the first time that new registers can also be declared at any later time in the circuit.
+ Note that we defined two very different styles:
+ \begin{itemize}
+ \item \texttt{/tikz/on} for the \texttt{tikzpicture} \\
+ This is an ordinary \TikZ{} style and hence will be applied whenever it is used in a styling context---for example, when added to the wire styles.
+ \item \texttt{/yquant/on} for the \texttt{yquant*} environment \\
+ This is a style that does not directly apply any styling, but it instead passes options to \style{/yquant/style} (we want to have the gates as well as their controls and control lines in red) as well as to \style{/yquant/control style} (we want to draw the control lines thicker [in principle, this would also affect the controls, but they are filled, not drawn], but we don't want to draw the lines of the \gate{cnot} gates themselves be drawn thicker.).
+ Since attributes for gates will first look in the \texttt{/yquant} namespace, this style is applied when used as an attribute for a gate (but beware that \yquant![style=on]! would call the other style).
+ \end{itemize}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}[register/default name=$\reg$]
+ cbit a;
+ qubit b;
+ h b | a;
+ discard a;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \Yquant{} does not offer the variety of shapes that \pkg{qpic} does; please file a feature request if there is a need.
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a;
+ qubit b;
+ [shape=yquant-circle, radius=1.2mm, inner sep=0pt]
+ box {$\cdot$} b | a;
+ box {$A$} (-);
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \clearpage
+ \begin{example}
+ \begin{codeexample*}
+% \usepackage[hidelinks]{hyperref}
+% \usetikzlibrary{calc}
+\makeatletter
+\def\tikzHyperNode#1{%
+ \ifdefined\tikz@alias%
+ \unless\ifyquantmeasuring%
+ \pgfqkeysalso{/tikz}{%
+ % https://tex.stackexchange.com/a/36111/32357
+ alias=sourcenode,
+ append after command={
+ % we don't need to worry about outer sep, yquant shapes ignore this value
+ let \p1=(sourcenode.north west),
+ \p2=(sourcenode.south east),
+ \n1={\x2-\x1},
+ \n2={\y1-\y2} in
+ node [inner sep=0pt, outer sep=0pt, anchor=north west, at=(\p1)]
+ {#1{\XeTeXLinkBox{\phantom{\rule{\n1}{\n2}}}}}
+ }%
+ }%
+ \fi%
+ \fi%
+}
+\tikzset{
+ hyperlink/.code={\tikzHyperNode{\hyperlink{#1}}},
+ hyperref/.code={\tikzHyperNode{\hyperref[{#1}]}}
+}
+
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a;
+ qubit b;
+ [hyperref=sec:grammar]
+ box {SUB} (a-b);
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample*}
+ In principle, adding a hyperlink to any gate works as adding a hyperlink to any \TikZ{} node.
+ We use a standard implementation; because of the way \Yquant{} internally handles styles applied to a gate, we must protect this in the \tex!\ifdefined\tikz@alias! (\Yquant{} executes the options outside of nodes first to set, e.g., line styles appropriately, which leads to an error, as the \texttt{alias} option only works within nodes).
+ We also want to refrain from unnecessarily adding hyperlinks during the initial measurement phase.
+ We then provide two \TikZ{} styles to do the job, depending on whether the link should be created via \tex!\hyperlink! or \tex!\hyperref! and apply it.
+ Note that here, we explicitly created the registers first.
+ Had we used an implicit creation, we would also have applied to hyperref to the register labels!
+
+ Be aware of the fact that hyperlinks in PDFs will always be rectangular; if your gate shape is different from this, do not expect the shapes to match.
+ \end{example}
+
+ \subsubsection{3.4 Measurement and Other Wire Type Changes}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ measure a;
+ cnot b | a;
+ dmeter {$Z$} b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \Yquant{} does not support the \texttt{tag} shape.
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [direct control] measure a;
+ cnot b | a;
+ dmeter {$Z$} b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[operator/separation=2mm]
+ setstyle {-|, shorten >= 3mm} a;
+ inspect {$0$} a;
+ discard a;
+
+ hspace {1cm} -;
+
+ setstyle {|-, shorten <= 2mm} a;
+ init {$1$} a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ There are no gates in \Yquant{} that resemble the visual \gate{discard} or reinitialization marker; however, this can be achieved by placing appropriate arrowheads at the wires.
+ Still, this is a problematic solution: Every wire in \Yquant{} will extend from the center of one gate to the center of the next gate; protruding parts will be clipped away.
+ Hence, the arrowhead will not be visible, as it is below the \gate{inspect} or \gate{init} gate---so we must \texttt{shorten} the wire by an ``appropriate'' amount.
+ Additionally, if the circuit were longer, we would want to quickly get rid of this arrowhead style.
+ \Yquant{} will try to make the wire lines as long as possible---i.e., in a normal circuit without any changes, the wire will in fact be one continuous line from the left to the right.
+ However, whenever something changes at the wire---say, the style or type is changed---\Yquant{} needs to start a new path.
+ We don't want the arrowheads to still be installed on this new path, hence we would quickly need to remove them.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a;
+ hspace {5mm} a;
+ [after=a] qubit b;
+ box {$f$} (a, b);
+ inspect {$A$} a;
+ [after=a] qubit c;
+ discard a;
+ box {$g$} (b, c);
+ align -;
+ init {$a'$} a;
+ inspect {$B$} b;
+ discard b;
+ box {$h$} (-);
+ output {$A'$} a;
+ output {$C'$} c;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ Here, we create registers with the \texttt{after} attribute at some later point in the circuit.
+ Note that logically speaking, the $h$~box should have had the targets \yquant!(a, c)!; however, as \Yquant{} does not know that the middle register was already discarded, it would have drawn two boxes joined by a wiggly line to indicate the discontiguous multi\hyp qubit register.
+ \end{example}
+
+ \subsubsection{3.5 Managing Slices}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b; qubit c; qubit d;
+ zz (a, c);
+ h b;
+ measure d;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b; qubit c; qubit d;
+ zz (a, c);
+ h b;
+ align -;
+ measure d;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b; qubit c; qubit d;
+ zz (a, c);
+ align -;
+ h b;
+ measure d;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \begin{yquant}[operators/every barrier/.style={shape=yquant-line, draw, shorten <= -2mm, shorten >= -2mm, decoration={zigzag, segment length=4, amplitude=1pt}, decorate}]
+ qubit a; qubit b; qubit c; qubit d;
+ zz (a, c);
+ h b;
+ align -;
+ barrier d;
+ measure d;
+ [red] barrier a, d;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample*}
+ Note that a \Yquant{} \gate{barrier} works a bit differently from \pkg{qpic}'s.
+ It is basically just an ordinary gate with a dashed line style; by the fact that all registers that are listed in the target list are aligned automatically, the \gate{barrier} usually does its job.
+ Hence, we need to \gate{align} before the first \gate{barrier}, as it does not perform an alignment by itself on registers that were not mentioned as targets.
+
+ Here, we also change the default style (which is a dashed line) to the zigzag line that uses \pkg{qpic}'s style.
+ Note that \Yquant{} automatically loads the library \texttt{decorations.pathmorphing}, so we don't need to do this.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[operator/minimum width=0pt, operator/separation=2mm]
+ [shape=yquant-circle, radius=1.5ex]
+ box {$2$} a | b;
+ h a, b, c;
+ [style=green!50!black]
+ cnot c | a, b;
+ [operator/separation=0pt, green!50!black]
+ not c;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ In order to stick two operators directly next to each other, we must set the \style{/yquant/operator/separation} to zero; this is the whitespace that is inserted before an operator.
+ However, if the total with of an operator is smaller than \style{/yquant/operator/minimum width}, it is centered in a box of this width (giving a more uniform layout with lots of small gates), which would add additional whitespace both to the right of the Hadamards and to the left of the \gate{cnot}s.
+ We just globally suppress this minimum width, which is unproblematic for this particular circuit (we could also locally change it).
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[operator/minimum width=0pt, operator/separation=2mm]
+ [shape=yquant-circle, radius=1.5ex]
+ box {$2$} a | b;
+ h a, b, c;
+ [style=red]
+ cnot c | a, b;
+ [operator/separation=0pt]
+ not c;
+ cnot c | a, b;
+ [operator/separation=0pt, red]
+ not c;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[operators/every box/.append style={shape=yquant-circle, radius=1.5ex}]
+ box {$1$} a;
+ not b;
+ box {$2$} a;
+ align -;
+ not b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ An instruction like \texttt{MIXGATES} does not exist in \Yquant, as it does not use a grid\hyp based layout; but of course, its behavior can be faked by \gate{align} gates.
+ \end{example}
+
+ \clearpage
+ \subsubsection{3.6 Reversing and Repeating}
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \yquantdefinegate{cnots}{
+ qubit a; qubit b; qubit c;
+ cnot b | a;
+ cnot b | c;
+ cnot a | b;
+ cnot c | b;
+ }
+ \begin{yquant*}
+ cnots (a, b, c);
+ cnots (-);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample*}
+ \Yquant{} does not have a concept of slices and hence can also not automatically repeat gates within a certain slice.
+ However, there are multiple ways to achieve the circuits in this section without repeating parts manually.
+ Here, we defined a custom gate that contained the content and inserted it two times.
+ Another alternative would be to do this using macros, as was illustrated in the \hyperref[ex:qupicfirst]{very first example} of the \pkg{qpic} section.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \yquantdefinegate{gates}{
+ qubit a; qubit b; qubit c;
+ [plusctrl] box {$f$} a | b;
+ addstyle {dotted} b;
+ [plusctrl] box {$g$} (a, b) | c;
+ [plusctrl] box {$f$} a | b;
+ addstyle {solid} b;
+ }
+ \begin{yquant*}[plusctrl/.style={/yquant/every control/.style={/yquant/operators/every not}, /yquant/every positive control/.style={}}]
+ gates (a, b, c);
+ cnot b | c;
+ gates (-);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample*}
+ Note that for this sequence, we did basically the same thing as before, as we identified a symmetric slice---so reversing the order does not do anything.
+
+ We will also expand this example and give a very simple (and a bit shortsighted) implementation of a macro that reverses the order of gates.
+ Note that this macro basically just splits its content at semicolons and when it is done inputs all the parts in reverse order.
+ Hence, it will fail if semicolons appear, e.g., in attributes without enclosing them in braces.
+ It also does not correspond exactly to the \texttt{R} instruction from \pkg{qpic}, as it does not \emph{reverse} wire styles (basically \gate{addstyle} would become a hypothetical \gate{subtractstyle} macro), but just inserts them in reverse order.
+ Hence, the following example will give a different circuit with respect to the wire style!
+
+ \begin{codeexample*}
+\makeatletter
+\long\def\reversegates#1{%
+ \begingroup%
+ \let\reversegates@list=\empty%
+ \count0=0 %
+ \expandafter\reversegates@i#1;\reversegates@stop%
+}
+\long\def\reversegates@i#1;#2\reversegates@stop{%
+ \ifstrempty{#2}{%
+ \yquant@fordown \reversegates@idx := \count0 downto 1 {%
+ \expandafter\expandafter\expandafter\yquant%
+ \csname reversegates@list@\reversegates@idx\endcsname%
+ }%
+ \endgroup%
+ }{%
+ \ifstrequal{#2}{;}{%
+ \reversegates@i;\reversegates@stop%
+ }{%
+ \advance\count0 by 1 %
+ \csdef{reversegates@list@\the\count0}{#1;}%
+ \reversegates@i#2\reversegates@stop%
+ }%
+ }
+}
+\begin{tikzpicture}
+ \def\gates{%
+ [plusctrl] box {$f$} a | b;
+ addstyle {dotted} b;
+ [plusctrl] box {$g$} (a, b) | c;
+ [plusctrl] box {$f$} a | b;
+ addstyle {solid} b;
+ }
+ \begin{yquant*}[plusctrl/.style={/yquant/every control/.style={/yquant/operators/every not}, /yquant/every positive control/.style={}}]
+ \expandafter\yquant\gates
+ cnot b | c;
+ \reversegates\gates
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample*}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b; qubit c;
+ cnot b | a;
+ cnot b | c;
+ \foreach \i in {1, 2} { \yquant
+ cnot a | b;
+ cnot c | b;
+ }
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ Another way to repeat things is to just use appropriate repetition macros (and remember to restart the parser); here, we used \tex!\foreach! from \TikZ, but any other will also do the job.
+ \end{example}
+
+ \subsubsection{3.7 Other Circuit Elements}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}[operators/every slash/.append style={radius=2mm}]
+ slash a;
+ [label=10:n] slash a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b;
+ cnot b | a;
+ inspect {\Ifcase\idx$a$\Else$a \oplus b$\Fi} -;
+ cnot b | a;
+ inspect {$b$} b;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ Here, we achieved the centering of the two \gate{inspect}ed registers by putting them in a single gate instruction with case discrimination.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ swap (a, b);
+ text {$=$} (-);
+ cnot b | a;
+ cnot a | b;
+ cnot b | a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ This is a very simple equality; for more complicated ones, the \hyperref[sec:foreign:groups]{\texttt{groups}} library is recommended.
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b; qubit c; qubit d;
+ box {$f$} (a, b);
+ inspect {$G$} (a, b);
+ init {$F$} (c, d);
+ box {$g$} (c, d);
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that we first defined all the registers explicitly, and they all use an initializing text.
+ Had we directly used the \gate{init} gate on the registers \yquant!(c, d)! as the \emph{first} gate when \emph{neither} of both registers had an initializing text, then the~$F$ would have been placed to the left of the wires.
+ Basically, a \gate{qubit} declaration with a value is the same as declaring the register without a value plus another \gate{init} gate that puts the value in place.
+ A zero\hyp length \gate{hspace} gate or an \gate{align}ment directly at the beginning would be a way to prevent this shift to the left from happening.
+ \end{example}
+
+ \Yquant{} does not support the permutation gate that \pkg{qpic} has.
+ It would however not be very difficult to implement this particular shape and make it available.
+ Maybe even a multi\hyp swap gate using the \texttt{knots} library would be possible.
+
+ \clearpage
+ \subsubsection{3.8 Comments}
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b;
+ \foreach \i in {0, 1, 2} { \yquant
+ cnot b | a;
+ cnot a | b;
+ \ifnum\i<2 \yquant
+ [operator/separation=2pt, operator/minimum width=0pt]
+ barrier (-);
+ \fi
+ }
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample*}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+% \usetikzlibrary{quotes}
+\begin{tikzpicture}
+ \begin{yquant}[operators/every box/.append style={shape=yquant-circle, radius=1.5ex}]
+ qubit a;
+ [blue, "above" above] box {$1$} a;
+ [red, "below" below] box {$2$} a;
+ ["both" above, "sides" below] box {$3$} a;
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample*}
+% \usetikzlibrary{calc}
+\begin{tikzpicture}
+ \begin{yquant}[operators/every box/.append style={shape=yquant-circle, radius=1.5ex}]
+ qubit a;
+ [name=1] box {$1$} a;
+ [name=2] box {$2$} a;
+ [name=3] box {$3$} a;
+ \end{yquant}
+ \draw[decoration=brace, decorate]
+ ($(1.north west)+(-.1,.1)$) -- ($(2.north east)+(.1,.1)$)
+ node[midway, above=1pt] {above};
+ \draw[blue, decoration={brace, mirror}, decorate]
+ ($(2.south west)+(-.1,-.1)$) -- ($(3.south east)+(.1,-.1)$)
+ node[midway, below=1pt] {below};
+\end{tikzpicture}
+ \end{codeexample*}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample*}
+\begin{tikzpicture}
+ \begin{yquant*}
+ [this subcircuit box style={draw=none, fill=red!40!white}]
+ subcircuit {
+ qubit {} a; qubit {} b;
+ cnot b | a;
+ cnot a | b;
+ } (a, b);
+ [this subcircuit box style={draw, dotted, rounded corners=10pt}]
+ subcircuit {
+ qubit {} a; qubit {} b;
+ cnot b | a;
+ cnot a | b;
+ } (b, c);
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample*}
+ \end{example}
+
+ \clearpage
+ \subsubsection{3.9 Macros and \LaTeX{} Code}
+ \begin{example}
+ \begin{codeexample}
+\begin{tikzpicture}[loud/.style={red, very thick}]
+ \yquantdefinebox{phase2}[loud, draw, shape=yquant-circle, radius=1.5ex]{$2$}
+ \begin{yquant*}
+ [style=loud]
+ phase2 a | b;
+ phase2 b;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ Note that here, we choose an alternative gate name, as there already is the built\hyp in gate \gate{phase}.
+ While we could overwrite it, this is generally a very bad idea.
+ Keep in mind that gate declarations are global and also that gates are case insensitive, so changing the capitalization would not help.
+ Finally note that when we define a style for a new gate, it only pertains to the \emph{gate} itself.
+ It is not possible to change styles external to the gate---such as control lines---within the gate definition itself.
+ \end{example}
+
+ \begin{example}
+ The following example in the \pkg{qpic} manual requires some additional thoughts.
+ It defines a custom gate with a variable number of target registers.
+ The \tex!\yquantdefinegate! interface does not officially allow for this, although some low\hyp level hacking can of course be done (a \emph{sorted} \pkg{etoolbox} list is provided in the macro \tex!\yquant@circuit@subcircuit@param!, which holds the internal indices of all currently involved target registers).
+
+ It is of course always possible to write some macros that output the required gate commands.
+ Looking at the particular example, it is actually not really necessary to define a gate that has a variable number of targets.
+ Rather, in \Yquant, one would define a new gate that just contains the two $\oplus$ symbols next to each other; the control line is drawn separately from the gate anyway.
+ This very straightforward description will unfortunately fail, for the following reason:
+ When a control line is drawn, \Yquant{} currently always draws it from the \texttt{center} anchor of the current shape upwards or downwards.
+ However, for the $\mathord\oplus\!\mathord\oplus$ shape, the control line point should actually be in the middle of the right $\oplus$.
+ This is an off\hyp center point, so we need some hacking to convince \Yquant{} to do this.
+ The following code is pretty long; we will therefore give parts of the code, followed by an explanation.
+
+ First of all, we define a shape (similar to what is done in \texttt{yquant-shapes.tex}) that holds the two $\oplus$es.
+ \begin{codeexample*}
+\makeatletter
+\pgfdeclareshape{yquant-doubleoplus}{%
+ \inheritsavedanchors[from=yquant-slash]%
+ \anchor{center}{\pgfqpoint{.5\dimexpr\xradius\relax}{0pt}}%
+ \foreach \anc in {north, east, south, west} {
+ \inheritanchor[from=yquant-rectangle]{\anc}
+ }
+ \anchor{north east}{\pgfqpoint{.853553\dimexpr\xradius\relax}
+ {.707107\dimexpr\yradius\relax}}%
+ \anchor{south east}{\pgfqpoint{.853553\dimexpr\xradius\relax}
+ {-.707107\dimexpr\yradius\relax}}%
+ \anchor{south west}{\pgfqpoint{-.853553\dimexpr\xradius\relax}
+ {-.707107\dimexpr\yradius\relax}}%
+ \anchor{north west}{\pgfqpoint{-.853553\dimexpr\xradius\relax}
+ {.707107\dimexpr\yradius\relax}}%
+ % The border anchor is a bit more tricky, we leave it out here
+ \backgroundpath{%
+ \pgf@relevantforpicturesizefalse%
+ \pgfpathmoveto{\pgfqpoint{-.5\dimexpr\xradius\relax}{\yradius}}%
+ \pgfpathlineto{\pgfqpoint{-.5\dimexpr\xradius\relax}{-\yradius}}%
+ \pgfpathmoveto{\pgfqpoint{.5\dimexpr\xradius\relax}{\yradius}}%
+ \pgfpathlineto{\pgfqpoint{.5\dimexpr\xradius\relax}{-\yradius}}%
+ \pgfpathmoveto{\pgfqpoint{-\xradius}{0pt}}%
+ \pgfpathlineto{\pgfqpoint{\xradius}{0pt}}%
+ \pgfpathellipse{\pgfqpoint{-.5\dimexpr\xradius\relax}{0pt}}%
+ {\pgfqpoint{.5\dimexpr\xradius\relax}{0pt}}%
+ {\pgfqpoint{0pt}{\yradius}}%
+ \pgf@relevantforpicturesizetrue%
+ \pgfpathellipse{\pgfqpoint{.5\dimexpr\xradius\relax}{0pt}}%
+ {\pgfqpoint{.5\dimexpr\xradius\relax}{0pt}}%
+ {\pgfqpoint{0pt}{\yradius}}%
+ }%
+ \clippath{%
+ \pgfpathellipse
+ {\pgfqpoint{-.5\dimexpr\xradius}{0pt}}
+ {\pgfqpoint{.5\dimexpr\xradius+\pgflinewidth}{0pt}}
+ {\pgfqpoint{0pt}{\dimexpr\yradius+.5\pgflinewidth\relax}}%
+ \pgfpathellipse
+ {\pgfqpoint{.5\dimexpr\xradius\relax}{0pt}}
+ {\pgfqpoint{.5\dimexpr\xradius+\pgflinewidth\relax}{0pt}}
+ {\pgfqpoint{0pt}{\dimexpr\yradius+.5\pgflinewidth\relax}}%
+ }%
+}
+ \end{codeexample*}
+ \input \minted@jobname.pyg % we need to execute all this again without the group
+ Nothing special happens in the first few lines (although the \texttt{center} anchor is now off\hyp center): We declare a new shape \texttt{yquant-doubleoplus}, inherit some saved anchors and anchors (for details, see the \TikZ{} manual, section~106.5.3, ``Command for Declaring New Shapes'').
+ The \texttt{x~radius} now corresponds to the \emph{diameter} of one of the circles, since we have two circles next to each other.
+ We do not define border anchors at the moment; they would require some additional computation, but in lots of scenarios, they are not necessary (as we would also not need most of the anchors, but it is always good to have them).
+ The clip path is also not very special, it just contains the shape that is to be clipped away; basically, both circles.
+ The background path deserves more attention.
+ We draw the two circles and the vertical and horizontal lines; but note that we disable the \pkg{pgf}'s size protocol for all but the right circle.
+ Hence, when this shape is used, \TeX{} and \Yquant{} will actually think that it only occupies space for the right circle; the left one will protrude in the margin.
+ (Actually, we could wrap this in a test such as \tex!\ifdefined\yquant@prefix! to only discard protocoling within a \texttt{yquant} environment, so that the shape is properly usable outside.)
+
+ Next, we must take care of re\hyp inserting this ``lost'' margin whenever the gate is used; and we also define a style that appropriately uses the shape:
+ \begin{codeexample*}
+\yquantset{
+ operators/every noffoli/.style={
+ shape=yquant-doubleoplus, x radius=2.6mm, y radius=1.3mm, draw
+ },
+ internal/noffoli shift/.code={%
+ \begingroup%
+ \expandafter\tikzset\expandafter{\yquant@draw@@style}%
+ \tikzset{/yquant/every operator, /yquant/operators/every noffoli, /yquant/this operator}%
+ \edef\cmd{%
+ \endgroup
+ \dimdef\noexpand\yquant@config@operator@sep{%
+ \yquant@config@operator@sep+
+ \pgfkeysvalueof{/tikz/x radius}%
+ }%
+ }%
+ \cmd
+ }
+}
+ \end{codeexample*}
+ \input \minted@jobname.pyg % we need to execute all this again without the group
+ The first style is almost a copy of the \style{/yquant/operators/every not} style, only with the new shape and a doubled \texttt{x~radius}.
+ The second style is more complicated: Protected in a group, it first sets all the custom style overwrites that a user may pass to the gate (e.g., the user may wish to overwrite the radii)---those are stored in the internal macro \tex!\yquant@draw@@style!.
+ Then, it applies the styles in the order as the gate would do it; note that an attribute such as \yquant![x radius=1cm]! would only add the directive to the \style{/yquant/this operator} style, but not apply it yet, therefore we now execute all the options that were stored previously.
+ As the final action that survives the group, we add the current value for the \texttt{x~radius} to the current value of the operator separation---this effectively enacts the proper placement of our gate.
+
+ Having defined those styles, we finally need to declare the gate itself, so that it can be used in a circuit:
+ \begin{codeexample*}
+\yquant@langhelper@declare@command
+ {noffoli}
+ {}
+ {%
+ \appto\yquant@attrs@remaining{,/yquant/internal/noffoli shift}%
+ \yquant@prepare
+ {}%
+ {/yquant/operators/every noffoli}%
+ }%
+\yquant@langhelper@setup@attrs{noffoli}{}{}
+ \end{codeexample*}
+ % those were global commands anyway
+ We call \tex!\yquant@langhelper@declare@command!, as for every standard gate declaration, with the desired name of the gate (\tex!{noffoli}!), the actions that are to be carried out \emph{before} the targets and controls are parsed (\tex!{}!), and the actions that are to be carried out once the targets and controls are known.
+ We append the style that we just defined to the list of attributes, and execute the gate preparation.
+ Finally, we also declare the attributes that this gate takes---no required and no optional attributes.
+
+ After all this work, which can be saved in some shared document and used whenever necessary, we can come to the application, which is now very straightforward.
+
+ \begin{codeexample}
+\begin{tikzpicture}
+ \begin{yquant*}
+ noffoli a | b, c;
+ [style=red] noffoli c | a, b;
+ noffoli b | a;
+ \end{yquant*}
+\end{tikzpicture}
+ \end{codeexample}
+ \end{example}
+
+ \begin{example}
+ \begin{codeexample}
+% \usetikzlibrary{backgrounds}
+\begin{tikzpicture}
+ \begin{yquant}
+ qubit a; qubit b;
+ [name=cn]
+ cnot b | a;
+ \draw[fill=blue] (cn) circle[radius=5pt];
+ box {FONT} (-);
+ [name=cn, fill=boxBlueBody]
+ cnot b | a;
+ \scoped[on background layer] \draw[fill=red] (cn) circle[radius=5pt];
+ \end{yquant}
+\end{tikzpicture}
+ \end{codeexample}
+ There are no special options to mix \TikZ{} code with \Yquant{} code, as this can be done natively at any time.
+ To draw at the position of another gate, just name the gate.
+ Note that---as was illustrated here---also using the same name multiple times is possible, in this case, the latter use overwrites the former.
+ There is no direct equivalent to the \texttt{PRETIKZ} option---the gate has to be drawn first in order to get its position.
+ However, \TikZ{} supports layers, so it is easy to draw something behind a gate: just put it on a background layer, e.g., the one provided by the \texttt{backgrounds} library.
+ Also note that here, we filled the second \gate{cnot} gate with our background color in order to give the same image as in the \pkg{qpic} manual.
+ The circle is not filled by default, hence the red ``outer'' circle would be visible also inside the \gate{cnot} circle.
+ \end{example}
+
+ The \texttt{HYPERTARGET} instruction can be directly reproduced in \TeX{} by just putting a \tex!\hypertarget! before the \texttt{tikzpicture}.
+ \endgroup
+
\section{Foreign language support and extensions}\label{sec:foreign}
\Yquant{} is built in various modules, so that it is not hard to use the quantum circuit rendering backend, but expose a different language frontend.
\compat{New in 0.3}\Yquant{} not only understands its own language, but also others.
@@ -3496,20 +4968,113 @@ $=$
\end{adjustbox}
}
- \section{Wishlist}
- This section contains some thoughts on future improvements and features.
- \begin{itemize}
- \item Support for more other languages. \\
- Since version~0.3, \Yquant{} understands \pkg{qasm}.
- It would be nice if \Yquant{} could also understand \texttt{OpenQASM} correctly.
- The way \texttt{OpenQASM} treats operations is a bit different from \Yquant{} and also \pkg{qasm}.
- Some machinery would be required to automatically carry out transversal gates; apart from that everything should be available in \Yquant.
- \item Vertical layout. \\
- Sometimes, long quantum circuits on a portrait page can be better represented in a vertical layout.
- Also if lots of explanations are to be added, this becomes problematic in the horizontal version.
- In principle, \Yquant's approach could allow for a simple key switch that changes horizontal to vertical.
- Currently, this is largely unsupported by all quantum circuit packages except for \pkg{qpic}.
- \end{itemize}
+ \section{Integration with other packages}
+ In general, \Yquant{} should not introduce incompatibilities with other packages.
+ However, the possibility to mix \Yquant{} code with arbitrary \TeX{} code may lead to certain expectations on how things should work, which may not always be met.
+ This is mainly due to the fact that \Yquant{} requires two passes of its content (see \cref{sec:pipeline}), as it has to measure the heights and depths of the individual gates.
+ Similar issues can for example also arise in \pkg{amsmath}'s \texttt{align} environment, which also has a measuring and a shipout stage.
+ If you run into an incompatibility using a macro from another package (or even plain \TeX), try the following:
+ \begin{enumerate}
+ \item Using a \TeX{} macro within \Yquant{} code will stop the \Yquant{} parser.
+ Hence, all gates following this macro will be ignored.
+ Did you remember to issue \tex!\yquant! in order to restart the parser after your macro? \\
+ \emph{Symptom:} No errors, but gates are missing
+ \item Is the macro robust?
+ Modern packages could automatically take care of this by a \tex!\protected! definition, but older ones may not.
+ Try to prefix the macro by \tex!\protect!. \\
+ \emph{Symptom:} Unexpected error messages
+ \item Does the macro depend on other macros defined \emph{within} the circuit?
+ The double pass may lead to problems.
+ If possible, define your macros outside of the \texttt{yquant} environment.
+ If this is not possible, make sure the definitions are expandable, then at measurement stage, \Yquant{} will do the expansion, so that you get the correct results. \\
+ \emph{Symptom:} Only the latest assignment will show up whenever the macro is used; the vertical spacing (for subcircuits, possibly also the horizontal spacing) may even be screwed.
+ \item Does the macro create output, using its own font?
+ If the output depends on the current position, this position will be completely wrong.
+ This is due to the fact that the macro is executed at the first pass only, where \Yquant{} does not know about any positions at all.
+ \compat{New in 0.6}The macro \tex!\yquantsecondpass! will defer its content so that it is executed only at the second pass, where positions are known.
+ It will also automatically restart the parser.
+ Note that \tex!\yquantsecondpass! will not expand its content.
+ If you need expansion, you may use \tex!\yquantesecondpass!, which uses \tex!\protected@edef!. \\
+ \emph{Symptom:} Content occurring in the wrong place or missing
+ \item Does the macro need to be executed at both passes?
+ There may be reasons for this, in particular if you use commands from \pkg{pgf}'s basic or system layer.
+ However, all custom macros will only be executed once, at the first pass.
+ \compat{New in 0.6}Wrap the macros in \tex!\yquantescape! in order to execute them both times.
+ The parser will automatically be restarted afterwards.
+ Note that \tex!\yquantescape! will not expand its content.
+ You may use \tex!\yquanteescape!, which will first expand its content using \tex!\protected@edef!.
+ Note that the content will first be executed, then stored for the second pass. \\
+ \emph{Symptom:} Content missing
+ \item If all of this did not work and the use case is interesting enough, please file a bug report.
+ \end{enumerate}
+
+ \subsection{\texorpdfstring{\TikZ}{TikZ}}
+ \Yquant{} is built on top of \TikZ{} an hence integrates well with \TikZ.
+ You can use all \tex!\path!-like comands as well as scopes and \Yquant{} will automatically take care of restarting the parser appropriately.
+ If it does not, this is very likely a bug, please file a report.
+
+ You should typically not use \tex!\tikzset!, as all changes made by this macro will only be executed in the first pass.
+ Instead, use \tex!\yquantset! and change the path appropriately: this macro will first store its argument (using \tex!\protected@edef!) for the second pass and then set the appropriate options also in the first pass.
+
+ Note that low\hyp level \pkg{pgf} functions are not altered by \Yquant; this would be highly inefficient.
+ \compat{New in 0.6}If you need to use them, wrap them in \tex!\yquantescape! or \tex!\yquanteescape!.
+
+ \subsection[\texorpdfstring{\pkg{beamer}}{beamer}]{\compat{New in 0.6}\pkg{beamer}}
+ \Yquant{} integrates with \pkg{beamer} overlays.
+ This means that you can use the overlay commands \tex!\only!, \tex!\alt!, \tex!\temporal!, \tex!\uncover!, \tex!\visible!, and \tex!\invisible! directly in your \Yquant{} code; the parser will automatically be restarted whenever necessary.
+ Note that the \texttt{*env} environments (\texttt{onlyenv}, \texttt{altenv}, \texttt{uncoverenv}, \texttt{visibleenv}, and \texttt{invisibleenv}) should \emph{not} be used within \Yquant{} code.
+
+ The macros \tex!\pause! and \tex!\uncover! are also supported to some degree (\tex!\uncover! with braces is fully supported).
+ They should work well in simple circuits, but unexpected results can be expected in more complex scenarios.
+ If you don't get appropriate results, use the aforementioned macros.
+
+ You may also use \tex!\note! inside \Yquant{} circuits.
+
+ Note that \Yquant{} does not overwrite the definitions of the \pkg{beamer} macros, which implies that you can also use them \emph{within} gates (e.g., for the \texttt{value} of a \gate{box}).
+ However, this means that the \Yquant{} parser must be running to detect these macros and take appropriate action.
+ Hence, if you interrupted the code via some special macros, make sure to restart the parser even if your next macro is, e.g., \tex!\only!.
+
+ Finally note that \tex!\only!, \tex!\alt!, and \tex!\temporal! are more special than the usual \Yquant\hyp code\hyp interrupting macros.
+ They will \emph{not} terminate the group that was opened for the current gate.
+ As a consequence, you can also use these macros for arguments.
+ Note that whenever you pass arguments to a gate using the \texttt{[<arguments>] <gate> <registers>;} syntax, the value of \texttt{<arguments>} is directly fed to \tex!\pgfkeys!, which \emph{does not} understand \pkg{beamer} macros.
+ Hence, you \emph{cannot} use, e.g., \tex!\only! \emph{within} the brackets.
+ However, you can wrap the arguments including the brackets as a whole in \tex!\only!---this happens before \Yquant{} relinquishes control to \tex!\pgfkeys! and therefore is executed as expected.
+ Since you can also pass multiple arguments to a gate by repeating \texttt{[<arguments>]}, this easily allows to combine arguments with and arguments without overlays.
+ \begin{example}[Using overlays for arguments]
+ \begin{minted}{tex}
+% \documentclass{beamer}
+\begin{frame}
+ \begin{tikzpicture}
+ \begin{yquant}
+ qubit a;
+ [fill=yellow]
+ \alt<2>{[draw=blue]}{[draw=green]}
+ \only<3>{[ultra thick]}
+ h a;
+ \end{yquant}
+ \end{tikzpicture}
+\end{frame}
+ \end{minted}
+ The Hadamard gate will always be filled yellow; its line color will be blue on the second frame and green on all other frames.
+ On the third frame, its line width is dramatically increased.
+ \end{example}
+
+% We have GitHub issues for this
+% \section{Wishlist}
+% This section contains some thoughts on future improvements and features.
+% \begin{itemize}
+% \item Support for more other languages. \\
+% Since version~0.3, \Yquant{} understands \pkg{qasm}.
+% It would be nice if \Yquant{} could also understand \texttt{OpenQASM} correctly.
+% The way \texttt{OpenQASM} treats operations is a bit different from \Yquant{} and also \pkg{qasm}.
+% Some machinery would be required to automatically carry out transversal gates; apart from that everything should be available in \Yquant.
+% \item Vertical layout. \\
+% Sometimes, long quantum circuits on a portrait page can be better represented in a vertical layout.
+% Also if lots of explanations are to be added, this becomes problematic in the horizontal version.
+% In principle, \Yquant's approach could allow for a simple key switch that changes horizontal to vertical.
+% Currently, this is largely unsupported by all quantum circuit packages except for \pkg{qpic}.
+% \end{itemize}
\section{Changelog}
\subsection*{2020-03-15: Version 0.1}
@@ -3556,7 +5121,7 @@ $=$
Separate register height into a height and depth key. \\
Introduce \texttt{overlay} key to disable height caluclation selectively. \\
Change register style declaration, so that this is now always equivalent to creating an unnamed register followed by an \gate{init} gate with the given text.
- Note: This may be a \textbf{breaking change} that cannot be compatibility\hyp protected---if you used \TeX{} conditionals involving \tex!\idx! for creation labels of registers, you will now need to either \tex!\protect! them all or just capitalize their first letter (which corresponds to auto\hyp\tex!protect!ed versions for \texttt{compat} at least \texttt{0.4}). \\
+ Note: This may be a \textbf{breaking change} that cannot be compatibility\hyp protected---if you used \TeX{} conditionals involving \tex!\idx! for creation labels of registers, you will now need to either \tex!\protect! them all or just capitalize their first letter (which corresponds to auto\hyp\tex!\protect!ed versions for \texttt{compat} at least \texttt{0.4}). \\
Now use nodes for \gate{init} and \gate{output} gates. \\
Change behavior of \gate{hspace} and \gate{align}: Now also extend if the wire is discarded afterwards. \\
Introduce the commands \tex!\Ifnum!, \tex!\Ifcase!, \tex!\Or!, \tex!\Else!, \tex!\Fi!, \tex!\Unless! and \tex!\The! available for use within gates that behave like auto\hyp\tex!\protect!ed versions of their plain \TeX{} equivalents.
@@ -3580,5 +5145,20 @@ $=$
\subsection*{2021-09-04: Version 0.5.1}
Bugfix: The \gate{xx} gate style was not made available since version~0.4-alpha.
+
+ \subsection*{2021-12-28: Version 0.6}
+ Bugfix: Support to set the \style{/yquant/operators/subcircuit/seamless} property outside of \Yquant{} environments. \\
+ New: Support for \pkg{beamer}. \\
+ New macros: \tex!\yquantsecondpass!, \tex!\yquantesecondpass!, \tex!\yquantescape!, and \tex!\yquanteescape! for more fine\hyp grained control of when to execute macros. \\
+ Bugfix: the auto\hyp\tex!\protect!ed versions \tex!\Ifnum! etc. now also work in \gate{output} gates. \\
+ New gate: \gate{text}. \\
+ Introduce the \style{/yquant/operators/every rectangular box} style as a common ancestor of gates such as \gate{box}, \gate{h}, ... instead of using the \style{/yquant/operators/every box} style for this.
+ As a consequence, boxes can now be styled globally without affecting the other gates.
+ This new behavior is compatibility\hyp protected. \\
+ Bugfix: \gate{output}s can now be named. \\
+ Bugfix: Border angles of \texttt{yquant-ellipse} now work properly. \\
+ New configuration: \style{/yquant/register/default lazy name} \\
+ Documentation: Replace the wishlist by a section on integration with other packages. \\
+ Documentation: Include the examples of \pkg{qpic} in this manual.
%END_FOLD
\end{document} \ No newline at end of file
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex b/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex
index 52cb435b2f..14f6a1f77b 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-circuit.tex
@@ -217,16 +217,18 @@
% restores the data captured for an uncontrolled operator and starts preparation
% #1: \yquant@attrs@remaining
-% #2: \yquant@circuit@operator@targets
-% #3: \yquant@circuit@operator@mintarget
-% #4: \yquant@circuit@operator@maxtarget
-% #5: \yquant@circuit@operator@numtarget
-\protected\def\yquant@circuit@restore#1#2#3#4#5{%
+% #2: \yquant@lang@attr@name
+% #3: \yquant@circuit@operator@targets
+% #4: \yquant@circuit@operator@mintarget
+% #5: \yquant@circuit@operator@maxtarget
+% #6: \yquant@circuit@operator@numtarget
+\protected\def\yquant@circuit@restore#1#2#3#4#5#6{%
\def\yquant@attrs@remaining{#1}%
- \def\yquant@circuit@operator@targets{#2}%
- \def\yquant@circuit@operator@mintarget{#3}%
- \def\yquant@circuit@operator@maxtarget{#4}%
- \def\yquant@circuit@operator@numtarget{#5}%
+ \def\yquant@lang@attr@name{#2}%
+ \def\yquant@circuit@operator@targets{#3}%
+ \def\yquant@circuit@operator@mintarget{#4}%
+ \def\yquant@circuit@operator@maxtarget{#5}%
+ \def\yquant@circuit@operator@numtarget{#6}%
\yquant@circuit@operator@hasControlsfalse%
\let\yquant@circuit@operator@pctrls=\empty%
\def\yquant@circuit@operator@minpctrl{2147483647}%
@@ -323,10 +325,20 @@
% sets the output of wires
% #1: arbitrary register list
\protected\def\yquant@circuit@output{%
- \protected\def\idx{}%
+ \let\idx=\yquant@protectedempty%
+ \ifnum\yquant@compat>1 %
+ \let\Ifnum=\yquant@protectedempty%
+ \let\Ifcase=\yquant@protectedempty%
+ \let\Or=\yquant@protectedempty%
+ \let\Else=\yquant@protectedempty%
+ \let\Fi=\yquant@protectedempty%
+ \let\Unless=\yquant@protectedempty%
+ \let\The=\yquant@protectedempty%
+ \fi%
\protected@csxappto{\yquant@prefix outputs}%
{\yquant@circuit@restore%
{\yquant@attrs@remaining}%
+ {\yquant@lang@attr@name}%
{\unexpanded\expandafter{\yquant@circuit@operator@targets}}%
{\yquant@circuit@operator@mintarget}{\yquant@circuit@operator@maxtarget}%
{\yquant@circuit@operator@numtarget}%
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-config.tex b/graphics/pgf/contrib/yquant/tex/yquant-config.tex
index a2d5a8fc9e..a50b2a4792 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-config.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-config.tex
@@ -43,7 +43,9 @@
% BEGIN_FOLD Register creation
\pgfqkeys{/yquant}{%
register/default name/.store in=%
- \yquant@config@register@default@name%
+ \yquant@config@register@default@name,%
+ register/default lazy name/.store in=%
+ \yquant@config@register@default@lazyname%
}
\ifnum\yquant@compat<2 %
\pgfqkeys{/yquant}{%
@@ -172,9 +174,25 @@
}
\fi
\pgfqkeys{/yquant}{%
- operators/every box/.style=%
- {shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm},%
+ operators/every text/.style=%
+ {shape=yquant-rectangle, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm}%
}
+\ifnum\yquant@compat<3 %
+ \pgfqkeys{/yquant}{%
+ % we did not have this style before 0.6, but for the ease of implementation, we just change the direction of inheritance---users of earlier compat versions will never use the style, so this is fully transparent
+ operators/every rectangular box/.style=%
+ {/yquant/operators/every box},%
+ operators/every box/.style=%
+ {shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm}%
+ }
+\else
+ \pgfqkeys{/yquant}{%
+ operators/every rectangular box/.style=%
+ {shape=yquant-rectangle, draw, align=center, inner xsep=1mm, x radius=2mm, y radius=2.47mm},%
+ operators/every box/.style=%
+ {/yquant/operators/every rectangular box}%
+ }
+\fi
\ifnum\yquant@compat<2 %
\pgfqkeys{/yquant}{%
operators/every custom gate/.style=%
@@ -200,7 +218,7 @@
operators/every not/.style=%
{shape=yquant-oplus, radius=1.3mm, draw},%
operators/every pauli/.style=%
- {/yquant/operators/every box},%
+ {/yquant/operators/every rectangular box},%
operators/every phase/.style=%
{shape=yquant-circle, radius=.5mm, fill},%
operators/every slash/.style=%
@@ -208,7 +226,7 @@
operators/every subcircuit/.style=%
{},%
operators/every subcircuit box/.style=%
- {/yquant/operators/every box},%
+ {/yquant/operators/every rectangular box},%
subcircuit box style/.style=%
{/yquant/operators/every subcircuit box/.append style={#1}},%
operators/this subcircuit box/.style=%
@@ -219,7 +237,11 @@
{/yquant/operators/this subcircuit box/.append style={draw=none, inner sep=0pt}},%
operators/subcircuit/seamless/.code=%
{\pgfkeysalso{/yquant/operators/subcircuit/frameless, /yquant/register/default name=}%
- \letcs\yquant@prevseamless{\yquant@prefix seamless}%
+ \ifdefined\yquant@prefix%
+ \csletcs{yquant@prevseamless}{\yquant@prefix seamless}%
+ \else%
+ \csletcs{yquant@prevseamless}{iffalse}%
+ \fi%
\yquant@config@circuit@seamlesstrue},
operators/subcircuit/name mangling/.is choice,%
operators/subcircuit/name mangling/prefix or discard/.code=%
@@ -270,6 +292,7 @@
% END_FOLD
\def\yquant@config@register@default@name{\regidx}
+\let\yquant@config@register@default@lazyname=\empty
\def\yquant@config@register@minimum@height{1.5mm}
\def\yquant@config@register@minimum@depth{1.5mm}
\def\yquant@config@register@sep{1mm}
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-env.tex b/graphics/pgf/contrib/yquant/tex/yquant-env.tex
index c6e9f52b01..f26919c8d1 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-env.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-env.tex
@@ -56,7 +56,7 @@
\edef\yquant@prefix{yquant@env\the\yquant@env @}%
\ifnum\yquant@env=1 %
\yquantmeasuringtrue%
- \yquant@env@substikz#1%
+ \yquant@env@substitute%
\global\cslet{\yquant@prefix parameters}\empty%
\else%
\let\yquant@lang@reset@attrs@inputoutput=\yquant@lang@reset@attrs@inputoutput@subcircuit%
@@ -529,8 +529,29 @@
\pgftransformreset%
}
+\protected\def\yquant@env@protectidx{%
+ \ifundef\idx{%
+ \let\idx=\yquant@protectedempty%
+ }\relax%
+ \ifundef\reg{%
+ \let\reg=\yquant@protectedempty%
+ }\relax%
+ \ifundef\regidx{%
+ \let\regidx=\yquant@protectedempty%
+ }\relax%
+ \ifundef\len{%
+ \let\len=\yquant@protectedempty%
+ }\relax%
+}
+
+\let\yquant@env@substitutions=\empty
+\def\yquant@env@substitute{%
+ \forlistloop\@firstofone\yquant@env@substitutions%
+}
+
% substitute the tikz commands (defined in \tikz@installcommands) so that they can be arbitrarily interleaved with yquant code. We patch \path, \scope, \endscope, \stopscope, their internal complements, and also patch \yquantset.
-\protected\def\yquant@env@substikz#1{%
+\listadd\yquant@env@substitutions\yquant@env@substikz
+\protected\def\yquant@env@substikz{%
% \tikz@path@do@at@end is called after a path. Hence, it is an ideal candidate to re-invoke \yquant@env@scan. However, it is by default defined to be \tikz@lib@scope@check, and we need this definition for the scopes library to work correctly. But since \tikz@lib@scope@check is also called after a scope and the end of a scope, this is even better. Yet, we need to check whether the scopes library is present or not.
\let\yquant@env@substikz@scopecheck=\tikz@lib@scope@check%
\ifx\tikz@lib@scope@check\pgfutil@empty%
@@ -547,25 +568,31 @@
\protected@csxappto{\yquant@prefix draw}{%
\noexpand\path##1;%
}%
- #1%
+ \yquant@env@scan%
}%
% no need for \scoped, because it internally calls \scope.
% We need to hack into \scope, but this is a bit tricky due to its argument handling. In order to get all optional arguments, including the possible animations library, correct, we change \tikz@scope@opt.
\ifdefined\tikz@scope@opt%
\let\yquant@env@substikz@scope=\tikz@scope@opt%
\def\tikz@scope@opt[##1]{%
- \protected@csxappto{\yquant@prefix draw}{%
- \noexpand\tikz@scope@env[{##1}]%
- }%
+ \begingroup%
+ \yquant@env@protectidx% scope options may contain \idx, \reg, and \regidx
+ \protected@csxappto{\yquant@prefix draw}{%
+ \noexpand\tikz@scope@env[{##1}]%
+ }%
+ \endgroup%
\yquant@env@substikz@scope[{##1}]%
}%
\else%
% this is for the arXiv, which has a very outdated version of TikZ
\let\yquant@env@substikz@scope=\tikz@@scope@env%
\def\tikz@@scope@env[##1]{%
- \protected@csxappto{\yquant@prefix draw}{%
- \noexpand\tikz@@scope@env[{##1}]%
- }%
+ \begingroup%
+ \yquant@env@protectidx% scope options may contain \idx, \reg, and \regidx
+ \protected@csxappto{\yquant@prefix draw}{%
+ \noexpand\tikz@@scope@env[{##1}]%
+ }%
+ \endgroup%
\yquant@env@substikz@scope[{##1}]%
}%
\fi%
@@ -580,14 +607,39 @@
\let\stopscope=\endscope%
% We define \yquantset as a pgfkeys-like macro. Anything else would deteriorate performance badly, as \pgfkeys, \pgfqkeys, or \tikzset are used a lot internally.
\protected\def\yquantset##1{%
- \protected@csxappto{\yquant@prefix draw}{%
- \noexpand\pgfqkeys{/yquant}{##1}%
- }%
+ \begingroup%
+ \yquant@env@protectidx% yquant options may contain \idx, \reg, and \regidx
+ \protected@csxappto{\yquant@prefix draw}{%
+ \noexpand\pgfqkeys{/yquant}{##1}%
+ }%
+ \endgroup%
\pgfqkeys{/yquant}{##1}%
\yquant@env@scan%
}%
}
+\listadd\yquant@env@substitutions\yquant@env@secondpass
+\protected\def\yquant@env@secondpass{%
+ \protected\long\def\yquantsecondpass##1{%
+ \csgappto{\yquant@prefix draw}{##1}%
+ \yquant@env@scan%
+ }%
+ \protected\long\def\yquantesecondpass##1{%
+ \protected@csxappto{\yquant@prefix draw}{##1}%
+ \yquant@env@scan%
+ }%
+ \protected\long\def\yquantescape##1{%
+ ##1%
+ \protected@csxappto{\yquant@prefix draw}{##1}%
+ \yquant@env@scan%
+ }%
+ \protected\long\def\yquanteescape##1{%
+ ##1%
+ \csgappto{\yquant@prefix draw}{##1}%
+ \yquant@env@scan%
+ }%
+}
+
% Scan until the next non-space token is found and execute it as a csname
\def\yquant@env@scan{%
\begingroup%
@@ -604,6 +656,230 @@
\yquant@env@scan%
}
+\ifdefined\beamer@masterdecode
+ \expandafter\@firstoftwo
+\else
+ \expandafter\@secondoftwo
+\fi{%
+ \protected\def\yquant@env@check@findmacro{%
+ % we only put the beamer macros in here that effectively remove things from the input stream. Everything that is typeset in a special way will end the group
+ \ifx\yquant@env@nextchar\only%
+ \let\next=\yquant@env@beamer@only%
+ \else%
+ \ifx\yquant@env@nextchar\alt%
+ \let\next=\yquant@env@beamer@alt%
+ \else%
+ \ifx\yquant@env@nextchar\temporal%
+ \let\next=\yquant@env@beamer@temporal%
+ \else%
+ \ifx\yquant@env@nextchar\note%
+ \let\next=\yquant@env@beamer@note%
+ \else%
+ % in principle: \endgroup for all in here, but need to preserve \yquant@env@nextchar
+ \ifx\yquant@env@nextchar\uncover%
+ \endgroup%
+ \let\next=\yquant@env@beamer@uncover%
+ \else%
+ \ifx\yquant@env@nextchar\visible%
+ \endgroup%
+ \let\next=\yquant@env@beamer@visible%
+ \else%
+ \ifx\yquant@env@nextchar\invisible%
+ \endgroup%
+ \let\next=\yquant@env@beamer@invisible%
+ \else%
+ \ifx\yquant@env@nextchar\onslide%
+ \endgroup%
+ \let\next=\yquant@env@beamer@onslide%
+ \else%
+ \ifx\yquant@env@nextchar\pause%
+ \endgroup%
+ \let\next=\yquant@env@beamer@pause%
+ \else%
+ \ifx\yquant@env@nextchar\yquant@env@beamer@checkifactive%
+ \endgroup%
+ \let\yquant@env@beamer@checkifactive@true=\relax%
+ \let\next=\relax%
+ \else%
+ \endgroup%
+ \let\next=\relax%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ \fi%
+ }%
+
+ \listadd\yquant@env@substitutions\yquant@env@substbeamer
+ \protected\def\yquant@env@substbeamer{%
+ \long\def\yquant@env@beamer@only@arga<##1>##2{%
+ \beamer@alt<##1>{\yquant@env@contscan##2}{\yquant@env@contscan}%
+ }%
+ \long\def\yquant@env@beamer@alt@arga<##1>##2##3{%
+ \beamer@alt<##1>{\yquant@env@contscan##2}{\yquant@env@contscan##3}%
+ }%
+ \protected\long\def\yquant@env@beamer@temporal\temporal<##1>##2##3##4{%
+ \temporal<##1>{\yquant@env@contscan##2}{\yquant@env@contscan##3}{\yquant@env@contscan##4}%
+ }%
+ % There's no need for the fakeinvisible or spacingcover macros, since we are within TikZ anyway
+ \mode<presentation>{
+ \protected\long\def\yquant@env@beamer@visibilitymacros##1##2##3##4{%
+ \yquant@env@beamer@visibilitymacros@flip##1%
+ \beamer@altget%
+ {\yquant@env@scan##3}%
+ {%
+ \begingroup%
+ \letcs\yquant@env@beamer@olddraw{\yquant@prefix draw}%
+ \global\cslet{\yquant@prefix draw}\empty%
+ \undef\yquant@env@beamer@checkifactive@true%
+ ##2{\yquant@env@scan##3\yquant@env@beamer@checkifactive}%
+ \csxdef{\yquant@prefix draw}{%
+ \unexpanded\expandafter{\yquant@env@beamer@olddraw}%
+ \ifx0##1%
+ \noexpand\beamer@alt##4{}%
+ \else%
+ \noexpand\beamer@only##4%
+ \fi%
+ {%
+ \unexpanded{##2}{%
+ \unexpanded\expandafter\expandafter\expandafter{\csname\yquant@prefix draw\endcsname}%
+ }%
+ }%
+ }%
+ \expandafter%
+ \endgroup%
+ \ifdefined\yquant@env@beamer@checkifactive@true%
+ \expandafter\@firstofone%
+ \else%
+ \expandafter\@gobble%
+ \fi%
+ \yquant@env@scan%
+ }%
+ ##4%
+ }
+ \newcommand<>\yquant@env@beamer@onslidenoargs[2]{%
+ \let\yquant@env@beamer@onslideappdraw=\empty%
+ \appto\yquant@env@beamer@onslideappdraw{\beamer@endpause}%
+ \yquant@for \i := 1 to \csname\yquant@prefix registers\endcsname{%
+ \eappto\yquant@env@beamer@onslideappdraw{\noexpand\yquant@circuit@flushwire{\i}}%
+ }%
+ \csxappto{\yquant@prefix draw}%
+ {\unexpanded\expandafter{\yquant@env@beamer@onslideappdraw}}%
+ \beamer@alt##3%
+ {\csgappto{\yquant@prefix draw}{%
+ \global\let\beamer@endpause=\empty%
+ }%
+ \yquant@env@scan}%
+ {\csgappto{\yquant@prefix draw}{%
+ ##1%
+ \gdef\beamer@endpause{##2}%
+ }%
+ \yquant@env@scan%
+ }%
+ }
+ % This is \beamer@inframenote, but we are always in a frame if we an in yquant
+ \newcommand<>{\yquant@env@beamer@note@}[2][]{%
+ \beamer@inframenote##3[{##1}]{##2}%
+ \yquant@env@contscan%
+ }
+ }%
+ \mode<article>{
+ \newcommand<>\yquant@env@beamer@uncover@[1]{%
+ \beamer@alt##2{\yquant@env@scan##1}{\yquant@env@scan}%
+ }
+ % we don't need \yquant@env@beamer@visible@ in this mode, since \uncover and \visible are equal (w.r.t. \ifx), so we will always end up with the \uncover path
+ \newcommand<>\yquant@env@beamer@invisible@[1]{%
+ \beamer@alt##2{\yquant@env@scan}{\yquant@env@scan##1}%
+ }
+ \newcommand<>{\yquant@env@beamer@note@}[2][]{\yquant@env@contscan}
+ \newrobustcmd\yquant@env@beamer@pause@[1][]{\yquant@env@scan}
+ }
+ \protected\def\yquant@env@beamer@onslide@{%
+ \@ifstar{\yquant@env@scan\only}%
+ {\@ifnextchar+{\expandafter\yquant@env@beamer@visibleonslide\@gobble}%
+ {\yquant@env@beamer@mainonslide}%
+ }%
+ }%
+ }
+
+ \protected\def\yquant@env@beamer@only\only{\@ifnextchar<{\yquant@env@beamer@only@arga}%
+ {\yquant@env@beamer@only@argb}}%
+ \long\def\yquant@env@beamer@only@argb#1{%
+ \beamer@ifnextcharospec{\yquant@env@beamer@only@argb@{#1}}{#1}%
+ }%
+ \long\def\yquant@env@beamer@only@argb@#1<#2>{%
+ \yquant@env@beamer@only@arga<#2>{#1}%
+ }%
+ \protected\def\yquant@env@beamer@alt\alt{\@ifnextchar<{\yquant@env@beamer@alt@arga}%
+ {\yquant@env@beamer@alt@argb}}%
+ \long\def\yquant@env@beamer@alt@argb#1#2{%
+ \beamer@ifnextcharospec{\yquant@env@beamer@alt@argb@{#1}{#2}}{#1}%
+ }
+ \long\def\yquant@env@beamer@alt@argb@#1#2<#3>{%
+ \yquant@env@beamer@alt@arga<#3>{#1}{#2}%
+ }
+
+ \def\yquant@env@beamer@checkifactive{%
+ % this should not compare to anything else, but should also not give an error on expansion
+ \yquant@env@beamer@checkifactive@%
+ }
+ \let\yquant@env@beamer@checkifactive@=\empty%
+ \def\yquant@env@beamer@note\note{\yquant@env@beamer@note@}
+ % note: in article mode, the definitions of \uncover and \visible are identical, hence we will mistake \visible for \uncover (which is checked first); therefore, \yquant@env@beamer@uncover may be followed by \uncover or \visible, just take an arbitrary argument.
+ \def\yquant@env@beamer@uncover#1{\yquant@env@beamer@uncover@}
+ \def\yquant@env@beamer@visible\visible{\yquant@env@beamer@visible@}
+ \def\yquant@env@beamer@invisible\invisible{\yquant@env@beamer@invisible@}
+ \def\yquant@env@beamer@onslide\onslide{\yquant@env@beamer@onslide@}
+ \def\yquant@env@beamer@pause\pause{\yquant@env@beamer@pause@}
+
+ \mode<presentation>{
+ \long\def\yquant@env@beamer@visibilitymacros@flip#1#2#3#4{%
+ \ifx1#1%
+ \expandafter\@firstoftwo%
+ \else%
+ \expandafter\@secondoftwo%
+ \fi%
+ {#2{#4}{#3}}{#2{#3}{#4}}%
+ }
+ \newcommand<>\yquant@env@beamer@uncover@[1]{%
+ \yquant@env@beamer@visibilitymacros0\beamer@makecovered{#1}{#2}%
+ }
+ \newcommand<>\yquant@env@beamer@visible@[1]{%
+ \yquant@env@beamer@visibilitymacros0\beamer@reallymakeinvisible{#1}{#2}%
+ }
+ \newcommand<>\yquant@env@beamer@invisible@[1]{%
+ \yquant@env@beamer@visibilitymacros1\beamer@reallymakeinvisible{#1}{#2}%
+ }
+ \newrobustcmd\yquant@env@beamer@pause@[1][]{%
+ \ifblank{#1}%
+ {\stepcounter{beamerpauses}}%
+ {\setcounter{beamerpauses}{#1}}%
+ \yquant@env@beamer@onslidenoargs<\value{beamerpauses}->\beamer@startcovered\beamer@endcovered%
+ }
+ }
+ \mode<article>{
+ \newcommand<>\yquant@env@beamer@onslidenoargs[2]{}
+ }
+ \newcommand<>{\yquant@env@beamer@visibleonslide}{%
+ \@ifnextchar\bgroup{\yquant@env@beamer@visible@#1}%
+ {\yquant@env@beamer@onslidenoargs#1\beamer@begininvisible\beamer@endinvisible}%
+ }
+ \newcommand<>{\yquant@env@beamer@mainonslide}{%
+ \@ifnextchar\bgroup{\yquant@env@beamer@uncover@#1}%
+ {\yquant@env@beamer@onslidenoargs#1\beamer@startcovered\beamer@endcovered}%
+ }
+}{%
+ \def\yquant@env@check@findmacro{%
+ \endgroup%
+ \let\next=\relax%
+ }
+}%
+
\protected\def\yquant@env@check@{%
\let\next=\relax%
% Here we assume standard catcodes for A and [, but our language specification also requires this implicitly.
@@ -625,8 +901,7 @@
\let\next=\yquant@env@gobblepar%
\else%
\ifcat\noexpand\yquant@env@nextchar\relax%
- \endgroup%
- \let\next=\relax%
+ \yquant@env@check@findmacro%
\else%
\PackageError{yquant.sty}%
{Invalid yquant syntax: `\meaning\yquant@env@nextchar'}%
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-lang.tex b/graphics/pgf/contrib/yquant/tex/yquant-lang.tex
index 8658d3af9f..cc882a7ffb 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-lang.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-lang.tex
@@ -298,7 +298,7 @@
% usually, we will not be in a tikzpicture here, so all the commands that abbreviate some path operation are undefined!
\tikz@installcommands%
% While we want the content to be expanded, protect the most likely TikZ commands - the same ones that we usually substitute in \yquant@env@substikz.
- \protected\def\path{}%
+ \let\path=\yquant@protectedempty%
\let\scoped=\path%
\let\scope=\path%
\let\endscope=\path%
@@ -362,7 +362,7 @@
\def\yquantdefinebox@#1#2{%
\@ifnextchar[{\yquantdefinebox@i{#1}{#2}}%
- {\yquantdefinebox@i{#1}{#2}[/yquant/operators/every box]}%
+ {\yquantdefinebox@i{#1}{#2}[/yquant/operators/every rectangular box]}%
}
\protected\long\def\yquantdefinebox@i#1#2[#3]#4{%
@@ -393,6 +393,16 @@
}
\yquant@langhelper@setup@attrs{box}{value}{}
+\yquant@langhelper@declare@command%
+ {text}%
+ \yquant@register@get@allowmultitrue%
+ {%
+ \expandafter\yquant@prepare%
+ \expandafter{\yquant@lang@attr@value}%
+ {/yquant/operators/every text}%
+ }
+\yquant@langhelper@setup@attrs{text}{value}{}
+
% Hadamard
\yquantdefinebox{h}{$H$}
@@ -601,6 +611,7 @@
{init}%
{%
\yquant@register@get@allowmultitrue%
+ \let\yquant@config@register@default@lazyname=\empty%
% we will count how many registers contain the "clean" flag, and only if this is equal to the number of targets, we apply the shift.
\count8=0 %
}%
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-prepare.tex b/graphics/pgf/contrib/yquant/tex/yquant-prepare.tex
index fb46e4e7d1..9869a61a76 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-prepare.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-prepare.tex
@@ -293,7 +293,7 @@
}
\protected\long\def\yquant@prepare@finalize#1#2{%
% We now know the dimensions of all the registers (though we didn't bother with the height of the control knobs [if present], we just assume they are too small to change this).
- \protected\def\idx{}%#
+ \let\idx=\yquant@protectedempty%
\yquant@prepare@ifs@set%
\let\yquant@prepare@append=\empty%
\yquant@sort\yquant@prepare@sort%
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-registers.tex b/graphics/pgf/contrib/yquant/tex/yquant-registers.tex
index 97762cf3dd..41a472821f 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-registers.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-registers.tex
@@ -166,9 +166,56 @@
\else%
\def\idx{0}%
\fi%
- % pre-set y position
- \yquant@for \idx := \idx to \numexpr \len -1\relax {%
- \yquant@prepare@create\reg\idx\yquant@register@type@q%
+ % define text macros
+ \ifnum\len=1 %
+ \let\regidx=\reg%
+ \else%
+ \def\regidx{\reg[\idx]}%
+ \fi%
+ \numdef\yquant@circuit@operator@mintarget{\csname\yquant@prefix registers\endcsname+1}%
+ \begingroup%
+ \yquant@for \idx := \idx to \numexpr \len -1\relax {%
+ \yquant@prepare@create\reg\idx\yquant@register@type@q%
+ }%
+ \endgroup%
+ \ifx\yquant@config@register@default@lazyname\empty%
+ \expandafter\@gobble%
+ \else%
+ \expandafter\@firstofone%
+ \fi%
+ {%
+ \let\yquant@lang@attr@value=\yquant@config@register@default@lazyname%
+ % gather details about the created registers
+ \letcs\yquant@circuit@operator@maxtarget{\yquant@prefix registers}%
+ \numdef\yquant@circuit@operator@numtarget{\yquant@circuit@operator@maxtarget-\yquant@circuit@operator@mintarget+1}%
+ \edef\yquant@circuit@operator@targets{%
+ \yquant@list@range%
+ \yquant@circuit@operator@mintarget%
+ \yquant@circuit@operator@maxtarget%
+ }%
+ \let\yquant@circuit@operator@pctrls=\empty%
+ \def\yquant@circuit@operator@minpctrl{2147483647}%
+ \def\yquant@circuit@operator@maxpctrl{0}%
+ \let\yquant@circuit@operator@numpctrl=\yquant@circuit@operator@maxpctrl%
+ \let\yquant@circuit@operator@nctrls=\empty%
+ \let\yquant@circuit@operator@minnctrl=\yquant@circuit@operator@minpctrl%
+ \let\yquant@circuit@operator@maxnctrl=\yquant@circuit@operator@maxpctrl%
+ \let\yquant@circuit@operator@numnctrl=\yquant@circuit@operator@numpctrl%
+ \let\yquant@circuit@operator@minctrl=\yquant@circuit@operator@mintarget%
+ \let\yquant@circuit@operator@maxctrl=\yquant@circuit@operator@maxtarget%
+ % there are no multi inits in this context
+ \preto\yquant@attrs@remaining{internal/move label,}%
+ \def\yquant@config@operator@minimum@width{0pt}%
+ \unless\ifx\yquant@lang@attr@value\empty%
+ % make sure to immediately remove the "clear" marker again if we have a text
+ \yquant@for \i := \yquant@circuit@operator@mintarget to \yquant@circuit@operator@maxtarget {%
+ \yquant@register@execclear@lastgate{\i}{init}%
+ }%
+ \fi%
+ \expandafter\yquant@prepare%
+ \expandafter{\yquant@lang@attr@value}%
+ {/yquant/every label, /yquant/every initial label,%
+ /yquant/every qubit label}%
}%
\endgroup%
}
@@ -216,8 +263,8 @@
}
\endgroup
-\protected\def\yquant@register@get@ids@@index{}
-\protected\def\yquant@register@get@ids@@multi{}
+\let\yquant@register@get@ids@@index=\yquant@protectedempty
+\let\yquant@register@get@ids@@multi=\yquant@protectedempty
\def\yquant@register@get@ids@outerlist#1{%
\ifyquant@firsttoken\yquant@register@get@ids@@multi{#1}{%
@@ -557,8 +604,8 @@
\yquant@register@get@id#1{\trim@spaces{#2}[\trim@spaces{\trim@spaces#3}]}%
}
-\let\yquant@register@multi=\empty%
-\protected\def\yquant@register@multi@contiguous{}%
+\let\yquant@register@multi=\empty
+\let\yquant@register@multi@contiguous=\yquant@protectedempty
% splits \yquant@register@get@ids@list into a list of contiguous parts
\protected\def\yquant@register@multi@splitparts{%
@@ -738,7 +785,7 @@
}
% This plays a similar role: It must never be expanded before the tikz command is invoked (because it does not exist).
-\protected\def\nodepart{}
+\let\nodepart=\yquant@protectedempty
\def\yquant@register@get@y@unprotected#1{%
\ifcsname\yquant@prefix registermap@#1\endcsname%
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex b/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex
index 88cddd66dd..ea62802b2b 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-shapes.tex
@@ -192,8 +192,7 @@
\@tempdima=\pgf@x%
\@tempdimb=\pgf@y%
\pgfpointborderellipse{\pgfqpoint{\@tempdima}{\@tempdimb}}%
- {\pgfqpoint{.707107\dimexpr\xradius\relax}%
- {.707107\dimexpr\yradius\relax}}%
+ {\pgfqpoint{\xradius}{\yradius}}%
}%
\backgroundpath{%
\pgfpathellipse{\pgfpointorigin}%
@@ -202,8 +201,8 @@
}%
\clippath{%
\pgfpathellipse{\pgfpointorigin}%
- {\pgfqpoint{\dimexpr\xradius+.5\pgflinewidth}{0pt}}%
- {\pgfqpoint{0pt}{\dimexpr\yradius+.5\pgflinewidth}}%
+ {\pgfqpoint{\dimexpr\xradius+.5\pgflinewidth\relax}{0pt}}%
+ {\pgfqpoint{0pt}{\dimexpr\yradius+.5\pgflinewidth\relax}}%
}%
}
diff --git a/graphics/pgf/contrib/yquant/tex/yquant-tools.tex b/graphics/pgf/contrib/yquant/tex/yquant-tools.tex
index 65880b995f..f30dc308bc 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant-tools.tex
+++ b/graphics/pgf/contrib/yquant/tex/yquant-tools.tex
@@ -37,6 +37,8 @@
\long\def\@fourthoffive#1#2#3#4#5{#4} % unused
\long\def\@fifthoffive#1#2#3#4#5{#5}
+\protected\def\yquant@protectedempty{}
+
% Loop #1 from min(#2, #3) to max(#2, #3), executing #4
\protected\def\yquant@for #1:=#2to#3#{%
\yquant@for@aux#1{#2}{#3}%
diff --git a/graphics/pgf/contrib/yquant/tex/yquant.sty b/graphics/pgf/contrib/yquant/tex/yquant.sty
index a3bda686b8..75b1cfd214 100644
--- a/graphics/pgf/contrib/yquant/tex/yquant.sty
+++ b/graphics/pgf/contrib/yquant/tex/yquant.sty
@@ -15,7 +15,7 @@
%
% The Current Maintainer of this work is Benjamin Desef.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{yquant}[2021/09/04 v0.5.1 Yet another quantum circuit library for LaTeX]
+\ProvidesPackage{yquant}[2021/12/28 v0.6 Yet another quantum circuit library for LaTeX]
\RequirePackage{etoolbox}[2018/02/11]
\RequirePackage{tikz}[2015/08/29]
@@ -23,16 +23,16 @@
\RequirePackage{xkeyval}[2005/05/07]
\usetikzlibrary{arrows.meta,decorations.pathreplacing,decorations.pathmorphing}
-\define@choicekey+{yquant.sty}{compat}[\val\yquant@compat]{newest,0.3,0.4}{
+\define@choicekey+{yquant.sty}{compat}[\val\yquant@compat]{newest,0.3,0.4,0.6}{
\ifnum\yquant@compat=0 %
- \def\yquant@compat{2} % current version
+ \def\yquant@compat{3} % current version
\fi%
}{
\PackageWarning{yquant.sty}{Invalid value for `compat` key specified. Using `0.3`.}
}
\ProcessOptionsX
\unless\ifdefined\yquant@compat
- \PackageWarning{yquant.sty}{Please specify the `compat` key for yquant. Using `0.3`. Current compatibility version `0.4`.}
+ \PackageWarning{yquant.sty}{Please specify the `compat` key for yquant. Using `0.3`. Current compatibility version `0.6`.}
\def\yquant@compat{1}
\fi
diff --git a/graphics/pgf/contrib/yquant/tex/yquantlanguage-groups.sty b/graphics/pgf/contrib/yquant/tex/yquantlanguage-groups.sty
index e8330d731e..1ea78cace6 100644
--- a/graphics/pgf/contrib/yquant/tex/yquantlanguage-groups.sty
+++ b/graphics/pgf/contrib/yquant/tex/yquantlanguage-groups.sty
@@ -15,9 +15,9 @@
%
% The Current Maintainer of this work is Benjamin Desef.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{yquantlanguage-groups}[2021/08/14 v0.5 yquant-groups]
+\ProvidesPackage{yquantlanguage-groups}[2021/08/14 v0.6 yquant-groups]
-\RequirePackage{yquant}[2021/08/14]
+\RequirePackage{yquant}[2021/12/24]
% BEGIN_FOLD Config
\newif\ifyquantgroup@config@aligned
@@ -173,7 +173,7 @@
\edef\yquant@prefix{yquant@env\the\yquant@env @}%
\ifnum\yquant@env=1 %
\yquantmeasuringtrue%
- \yquant@env@substikz#1%
+ \yquant@env@substitute%
\global\cslet{\yquant@prefix parameters}\empty%
\else%
\let\yquant@lang@reset@attrs@inputoutput=\yquant@lang@reset@attrs@inputoutput@subcircuit%
@@ -188,7 +188,7 @@
\let\yquant@parent=\yquantgroup@parent%
\let\yquant@prefix=\yquantgroup@prefix%
\yquantmeasuringtrue%
- \yquant@env@substikz#1%
+ \yquant@env@substitute%
\global\cslet{\yquant@prefix parameters}\empty%
}\relax{%
\PackageError{yquant.sty}{Internal error}%
diff --git a/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty b/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty
index d37aa6b9f0..86128e643c 100644
--- a/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty
+++ b/graphics/pgf/contrib/yquant/tex/yquantlanguage-qasm.sty
@@ -1,7 +1,7 @@
% yquantlanguage-qasm.sty
% Extend yquant to understand qasm syntax.
%
-% Copyright 2020 Benjamin Desef
+% Copyright 2021 Benjamin Desef
%
% This work may be distributed and/or modified under the conditions of the LaTeX Project
% Public License, either version 1.3c of this license or (at your option) any later
@@ -15,9 +15,9 @@
%
% The Current Maintainer of this work is Benjamin Desef.
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{yquantlanguage-qasm}[2021/03/27 v0.4 yquant-qasm]
+\ProvidesPackage{yquantlanguage-qasm}[2021/12/24 v0.6 yquant-qasm]
-\RequirePackage{yquant}[2021/03/27]
+\RequirePackage{yquant}[2021/12/24]
% BEGIN_FOLD Environment definitions
\begingroup
@@ -338,13 +338,13 @@
% BEGIN_FOLD Configuration
\pgfkeys{%
/yquant/operators/every s/.style={%
- /yquant/operators/every box%
+ /yquant/operators/every rectangular box%
},%
/yquant/operators/every t/.style={%
- /yquant/operators/every box%
+ /yquant/operators/every rectangular box%
},%
/yquant/operators/every utwo/.style={%
- /yquant/operators/every box%
+ /yquant/operators/every rectangular box%
},
/qasm/zero/.store in=%
\qasm@config@zero,%
diff --git a/graphics/pstricks/contrib/pst-geometrictools/Changes b/graphics/pstricks/contrib/pst-geometrictools/Changes
new file mode 100644
index 0000000000..535e2ec7f6
--- /dev/null
+++ b/graphics/pstricks/contrib/pst-geometrictools/Changes
@@ -0,0 +1,6 @@
+pst-geometrictools.tex ----------------
+
+1.3 2021/12/28 - more fixes for lualatex (hv)
+1.2 2021/11/17 - fixes for lualatex (hv)
+1.1 2017/09/16 - choose fonts for some tools
+1.0 2017/06/29
diff --git a/graphics/pstricks/contrib/pst-geometrictools/Changes.txt b/graphics/pstricks/contrib/pst-geometrictools/Changes.txt
deleted file mode 100644
index ce16d2fcb1..0000000000
--- a/graphics/pstricks/contrib/pst-geometrictools/Changes.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-pst-geometrictools.tex ----------------
-
-1.1 2017/09/16
-- choose fonts for some tools
-1.0 2017/06/29
diff --git a/graphics/pstricks/contrib/pst-geometrictools/README.md b/graphics/pstricks/contrib/pst-geometrictools/README.md
index c8bd792060..c3b26509db 100644
--- a/graphics/pstricks/contrib/pst-geometrictools/README.md
+++ b/graphics/pstricks/contrib/pst-geometrictools/README.md
@@ -1,8 +1,8 @@
The pst-geometrictools package Author: Thomas Söll
-`pst-geometrictools' is a PSTricks package to draw a protractor, a ruler, a compass and pencils
+"pst-geometrictools" is a PSTricks package to draw a protractor, a ruler, a compass and pencils
-Dated: 2017/09/16 Version 1.1
+Dated: 2021/12/28 Version 1.3
pst-geometrictools contains the following:
@@ -18,15 +18,15 @@ Save the files pst-geometrictools.sty|tex in a directory, which is part of your
local TeX tree.
Then do not forget to run texhash to update this tree.
For more information see the documentation of your LATEX distribution
-on installing packages into your local TeX system or read the
-TeX Frequently Asked Questions:
-(http://www.tex.ac.uk/cgi-bin/texfaq2html?label=instpackages).
+on installing packages into your local TeX system
pst-geometrictools needs pst-eucl, pstricks-xkey and pstricks, which should
be part of your local TeX installation, otherwise get it from a
-CTAN server, http://mirror.ctan.org
+CTAN server, https://mirror.ctan.org
-PSTricks is PostScript Tricks, the documentation cannot be run
-with pdftex, use the sequence latex->dvips->ps2pdf or latex->dvips->distiller.
+PSTricks is PostScript Tricks, the documentation cannot be run with pdftex,
+use the sequence latex->dvips->ps2pdf or latex->dvips->distiller or lualatex.
T. Söll
+
+(Bugfixes by Herbert Voß hvoss@tug.org)
diff --git a/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.pdf b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.pdf
new file mode 100644
index 0000000000..ce1b9782c2
--- /dev/null
+++ b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.pdf
Binary files differ
diff --git a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.tex b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.tex
index f646e7520f..47b04b6f2d 100644
--- a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.tex
+++ b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-doc.tex
@@ -20,33 +20,16 @@
\listfiles
-
-\documentclass[%
-11pt,
-english,
-BCOR10mm,
-DIV12,
-bibliography=totoc,
-parskip=false,
-fleqn,
-smallheadings,
-headexclude,
-footexclude,
-oneside,
-dvipsnames,
-svgnames,
-x11names,
-distiller
-]{pst-doc}
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+%% $Id: pst-venn-doc.tex 848 2018-12-04 09:25:49Z herbert $
+\documentclass[fontsize=11pt,english,BCOR=10mm,DIV=12,bibliography=totoc,parskip=false,headings=small,
+ headinclude=false,footinclude=false,oneside]{pst-doc}
\usepackage[autostyle]{csquotes}
-\usepackage{biblatex}
-%\usepackage[style=dtk]{biblatex}
-\addbibresource{pst-geometrictools-doc.bib}
-\usepackage[utf8]{inputenc}
+%\addbibresource{pst-geometrictools-doc.bib}
\let\pstpersFV\fileversion
-\usepackage{pst-geometrictools,pst-node,pst-eucl,pst-pers,pstricks-add,animate}
-\usepackage{etex} % increase the number of registers (otherwise only 256)
+\usepackage{pst-geometrictools,pst-node,pstricks-add,animate}
\let\belowcaptionskip\abovecaptionskip
@@ -71,22 +54,18 @@ distiller
\begin{document}
-\title{pst-geometrictools v 1.1}
+\title{pst-geometrictools v 1.3}
\subtitle{A PSTricks package to draw a protractor, a ruler, a compass and pencils}
-\author{Thomas \textsc{Söll}}
+\author{Thomas Söll\\Herbert Voß (bugfix)}
\date{\today}
-\maketitle
+\settitle
\tableofcontents
-\psset{unit=1cm}
-
-
-\clearpage
-
\begin{abstract}
-The package \LPack{pst-geometrictools} offers some customizable options to setup a \emph{protractor}, a \emph{ruler}, a \emph{compass} and \emph{pencils} to the users' wishes. Some geometric tools are predefined
+The package \LPack{pst-geometrictools} offers some customizable options to setup a \emph{protractor}, a \emph{ruler},
+a \emph{compass} and \emph{pencils} to the users' wishes. Some geometric tools are predefined
and ready-to-use for the customer to be able to present some pixel-free graphics showing the handling of some geometric tools.
The geometric tools can be scaled, rotated, positioned, colored as wanted, even labeled---if wanted.
@@ -97,12 +76,13 @@ We recommend to use the package \LPack{pst-eucl} (by \textit{Dominique Rodriguez
Have fun to use it!
-\vfill
+\bigskip
This program can redistributed and/or modified under the terms of the LaTeX Project Public License Distributed from CTAN archives in directory macros/latex/base/lppl.txt;
either version 1.3c of the License, or (at your option) any later version.
\end{abstract}
+
\clearpage
@@ -111,8 +91,7 @@ either version 1.3c of the License, or (at your option) any later version.
\subsection{\textbackslash psProtractor}
\begin{BDef}
-\Lcs{psProtractor}\OptArgs\Largb{angle}\Largr{coordinates of the origin}
-\\
+\Lcs{psProtractor}\OptArgs\Largb{angle}\Largr{coordinates of the origin}\\
\Lcs{psProtractor}\OptArgs\Largb{angle}\Largr{coordinates of the origin}\Largr{coordinates of a second point}
\end{BDef}
@@ -181,8 +160,7 @@ The command \Lcs{psRuler} offers a positioning
\subsection{\textbackslash psCompass}
\begin{BDef}
-\Lcs{psCompass}\OptArgs\Largb{radius}\Largr{coordinates of origin}
-\\
+\Lcs{psCompass}\OptArgs\Largb{radius}\Largr{coordinates of origin}\\
\Lcs{psCompass}\OptArgs\Largb{radius}\Largr{coordinates of origin}\Largr{coordinates of a second point}
\end{BDef}
@@ -238,13 +216,14 @@ The command \Lcs{psPencil} contains the options \nxLkeyword{PenScale=}, \nxLkeyw
\newpage
+
\subsection{\textbackslash psParallels (Idea and realization by \emph{Manuel Luque})}
\begin{BDef}
-\Lcs{psParallels}\OptArgs\Largr{pointA}\Largr{pointB}\Largr{pointC}\Largb{angle}
+\Lcs{psParallels}\OptArgs\Largr{pointA}\Largr{pointB}\Largr{pointC}
\end{BDef}
-The command \Lcs{psParallels} contains the option \nxLkeyword{DistCoeff=}.
+The command \Lcs{psParallels} contains the option \nxLkeyword{DistCoeff}.
\begin{quote}
\begin{tabularx}{\linewidth}{ @{} l >{\ttfamily}l X @{} }\toprule
@@ -254,18 +233,36 @@ The command \Lcs{psParallels} contains the option \nxLkeyword{DistCoeff=}.
\end{tabularx}
\end{quote}
-This command is made to directly draw a line parallel to the line containing \texttt{pointA} and \texttt{pointB} intersecting at point \texttt{pointC}.
-
-\begin{LTXexample}[pos=t,width=17cm]
-\begin{pspicture}(-11,-10)(6,2.5)
-\psParallels[DistCoeff=1](-6,-1)(1,2)(2,0)
-\end{pspicture}
+This command is made to directly draw a line parallel to the line containing \texttt{pointA} and \texttt{pointB}
+intersecting at point \texttt{pointC}.
+
+
+\begin{LTXexample}[pos=t,width=\linewidth]
+\psscalebox{0.5}{%
+\begin{pspicture}[showgrid=false](-15,-10)(5,3)%
+ \pnode(-6,1){A}\uput[100](A){A}
+ \pnode(1,2){B}\uput[100](B){B}
+ \pnode(2,0){C}\uput[90](C){C}
+ \pcline[linecolor=BrickRed,nodesepA=-2,nodesepB=-2](A)(B)%
+ \psParallels[style=Parallelen,RulerScale=0.5,ProScale=1,DistCoeff=1](A)(B)(C)
+ \pcline[linecolor=BrickRed](GeodrB)(GeodrA)%
+ \midAB(GeodrB)(GeodrA){M}%
+ \psPencil[PenLength=5,pencilColA=red,PenScale=0.5]{60}(M)
+ \end{pspicture}}
\end{LTXexample}
-The command \verb+\psParallels[DistCoeff=1](A)(B)(C){angle}+ allows to draw a parallel through the point C with the help of a ruler and protractor. The angle is the one between the pencil and the vertical.
-The command uses the option [DistCoef=] as within pst-eucl. If [DistCoef=0] the hypotenuse of the protractor lays on the line (AB), the ruler automatically positions below the protractor.
-For an animation, we vary [DistCoef=0..1], the protractor moves along the ruler letting the hypotenuse parallel to the line (AB). If [DistCoef=1], the protractor intersects with the point C. We can now draw the parallel to (AB) intersecting C.
+The command \verb+\psParallels[DistCoeff=1](A)(B)(C){angle}+ allows to draw a parallel through the
+point C with the help of a ruler and protractor. The angle is the one between the pencil and the vertical.
+The command uses the option [DistCoef=] as within pst-eucl. If [DistCoef=0] the hypotenuse of the
+protractor lays on the line (AB), the ruler automatically positions below the protractor.
+
+For an animation, we vary [DistCoef=0..1], the protractor moves along the ruler letting the
+hypotenuse parallel to the line (AB). If [DistCoef=1], the protractor intersects with the point C.
+We can now draw the parallel to (AB) intersecting C.
+
+
+
\newpage
@@ -274,12 +271,13 @@ For an animation, we vary [DistCoef=0..1], the protractor moves along the ruler
\section{Basic Examples}
\begin{LTXexample}[pos=t,width=16cm]
-\begin{pspicture}*(-6,-5.5)(10,7)
+\psscalebox{0.7}{%
+\begin{pspicture}[showgrid=false](-6,-5.5)(10,7)
\psProtractor{0}(0,0)% origin of the protractor
\psRuler{0}(0,0)% origin of the ruler
\psPencil{-30}(6,0)% origin of the pencil
\psCompass{3}(2,0)% origin of the compass
-\end{pspicture}
+\end{pspicture}}
\end{LTXexample}
We see, that the origins of the \emph{protractor} and \emph{ruler}, \emph{compass} and respectively the \emph{cone end of the pencil} are positioned at $(0|0)$, $(2|0)$, $(6|0)$. Adding an angle rotates the objects around their origins.
@@ -473,11 +471,11 @@ Constructing the height of a given triangle.
\clearpage
-\nocite{*}
-\bgroup
-\RaggedRight
-\printbibliography
-\egroup
+%\nocite{*}
+%\bgroup
+%\RaggedRight
+%\printbibliography
+%\egroup
\printindex
diff --git a/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.pdf b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.pdf
new file mode 100644
index 0000000000..2d8390e783
--- /dev/null
+++ b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.pdf
Binary files differ
diff --git a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.tex b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.tex
index 18fcfab3b8..4e36c902d1 100644
--- a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.tex
+++ b/graphics/pstricks/contrib/pst-geometrictools/doc/pst-geometrictools-fr-doc.tex
@@ -21,32 +21,18 @@
\listfiles
-\documentclass[%
-11pt,
-english,
-BCOR10mm,
-DIV12,
-bibliography=totoc,
-parskip=false,
-fleqn,
-smallheadings,
-headexclude,
-footexclude,
-oneside,
-dvipsnames,
-svgnames,
-x11names,
-distiller
-]{pst-doc}
+\RequirePackage{pdfmanagement-testphase}
+\DeclareDocumentMetadata{}
+%% $Id: pst-venn-doc.tex 848 2018-12-04 09:25:49Z herbert $
+\documentclass[fontsize=11pt,english,BCOR=10mm,DIV=12,bibliography=totoc,parskip=false,headings=small,
+ headinclude=false,footinclude=false,oneside]{pst-doc}
\usepackage[autostyle]{csquotes}
\usepackage{biblatex}
%\usepackage[style=dtk]{biblatex}
-\addbibresource{pst-geometrictools-doc.bib}
-\usepackage[utf8]{inputenc}
+%\addbibresource{pst-geometrictools-doc.bib}
\let\pstgeometrictoolsFV\fileversion
-\usepackage{pst-geometrictools,pst-node,pst-eucl,pstricks-add}
-\usepackage{etex} % increase the number of registers (otherwise only 256)
+\usepackage{pst-geometrictools,pst-node,pstricks-add}
\let\belowcaptionskip\abovecaptionskip
@@ -70,19 +56,14 @@ distiller
\begin{document}
-\title{pst-geometrictools v 1.0}
+\title{pst-geometrictools v 1.3}
\subtitle{Package de PSTricks pour dessiner un rapporteur, une r\'{e}glette et un crayon}
-\author{Thomas \textsc{S\"{o}ll}}
+\author{Thomas Söll\\Herbert Voß (bugfixes)}
\date{\today}
-\maketitle
+\settitle
\tableofcontents
-\psset{unit=1cm}
-
-
-\clearpage
-
\begin{abstract}
Pour illustrer des notions de g\'{e}om\'{e}trie \'{e}l\'{e}mentaire le package pst-geometrictools dispose des outils suivants :
@@ -93,7 +74,7 @@ Pour illustrer des notions de g\'{e}om\'{e}trie \'{e}l\'{e}mentaire le package p
\end{itemize}
Les arguments et options des commandes d\'{e}di\'{e}es permettent de les positionner ainsi que de les personnaliser. Vous remarquerez dans les exemples qui illustrent la documentation le soin tout professionnel qui a \'{e}t\'{e} apport\'{e} au dessin et aux d\'{e}tails des outils. L'utilisation du package pst-eucl de Dominique Rodriguez est vivement conseill\'{e} car ses commandes sont particuli\`{e}rement efficaces pour cr\'{e}er facilement des animations et des illustrations.
-\vfill
+\bigskip
This program can redistributed and/or modified under the terms of the LaTeX Project Public License Distributed from CTAN archives in directory macros/latex/base/lppl.txt; either version 1.3c of the License, or (at your option) any later version.
\end{abstract}
@@ -223,30 +204,43 @@ La commande \Lcs{psParallels} dispose des options \nxLkeyword{Ruler=}, \nxLkeywo
Cette commande permet de tracer la parrall\`{e}le passant par le point \texttt{pointC} \`{a} la droite d\'{e}finie par les points \texttt{pointA} and \texttt{pointB}. Le rapporteur et la r`{e}gle sont plac\'{e}s automatiquement.
-\begin{LTXexample}[pos=t,width=18cm]
-\begin{pspicture}[showgrid](-11,-4)(7,8)%
-\pstGeonode[PosAngle=135,linecolor=red](5,5){A}
-\pstGeonode[PosAngle=135,linecolor=Green](-8,1){B}
-\pstGeonode[PosAngle=-45,linecolor=blue](3,3){C}
-\pcline[linecolor=BrickRed,nodesepA=-2,nodesepB=-2](A)(B)%
-\psParallels[style=Parallelen,RulerScale=0.75,ProScale=0.75](A)(B)(C)
-\pcline[linecolor=BrickRed](GeodrB)(GeodrA)%
-\midAB(GeodrB)(GeodrA){M}%
-\psPencil[PenLength=5,pencilColA=red,PenScale=0.5]{60}(M)
+
+\begin{LTXexample}[pos=t,width=17cm]
+\begin{pspicture}(-11,-10)(6,2.5)
+\psParallels[DistCoeff=1,ProScale=.75,RulerScale=0.7](-6,-1)(1,2)(2,0)
\end{pspicture}
\end{LTXexample}
-Pour une animation, on utilisera la commande \verb+\multido{}{N}{...+ en fixant uniquement le nombre de pas souhait\'{e} pour que l'hypoth\'{e}nuse du rapporteur passe de la position o\`{u} il est tout pr\`{e}s de (AB) et parall\'{e}le \`{a} celle-ci au point C.
+
+\psset{unit=1cm}
+
+\begin{LTXexample}[pos=t,width=18cm]
+\psscalebox{0.5}{%
+\begin{pspicture}[showgrid](-11,-1)(11,20)%
+\pnode(5,5){A}\uput[90](A){A}
+\pnode(-8,1){B}\uput[90](B){B}
+\pnode(3,3){C}\uput[250](C){C}
+\pcline[linecolor=BrickRed,nodesepA=-2,nodesepB=-2](A)(B)
+\psParallels[style=Parallelen,RulerScale=0.75,ProScale=0.75](A)(B)(C)
+\pcline[linecolor=BrickRed](GeodrB)(GeodrA)%
+\midAB(GeodrB)(GeodrA){M}%
+\psPencil[PenLength=5,pencilColA=red,PenScale=0.5]{60}(M)
+\end{pspicture}}
+\end{LTXexample}
+
+Pour une animation, on utilisera la commande \verb+\multido{}{N}{...+ en fixant uniquement
+le nombre de pas souhait\'{e} pour que l'hypothénuse du rapporteur passe de la position
+où il est tout près de (AB) et parallèle à celle-ci au point C.
\begin{verbatim}
-\multido{}{40}{
-\begin{pspicture}[showgrid](-11,-4)(7,8)%
-\pstGeonode[PosAngle=135,linecolor=red](-2,6){A}
-\pstGeonode[PosAngle=135,linecolor=Green](-8,1){B}
-\pstGeonode[PosAngle=-45,linecolor=blue](0,3){C}
-\pcline[linecolor=BrickRed,nodesepA=-2,nodesepB=-2](A)(B)%
-\psParallels[style=Parallelen,RulerScale=0.75,ProScale=0.75](A)(B)(C)
-\end{pspicture}
+\multido{}{40}{%
+ \begin{pspicture}[showgrid](-11,-4)(7,8)%
+ \pstGeonode[PosAngle=135,linecolor=red](-2,6){A}
+ \pstGeonode[PosAngle=135,linecolor=Green](-8,1){B}
+ \pstGeonode[PosAngle=-45,linecolor=blue](0,3){C}
+ \pcline[linecolor=BrickRed,nodesepA=-2,nodesepB=-2](A)(B)%
+ \psParallels[style=Parallelen,RulerScale=0.75,ProScale=0.75](A)(B)(C)
+ \end{pspicture}%
}
\end{verbatim}
@@ -404,11 +398,11 @@ Construction des hauteurs d'un triangle
\clearpage
-\nocite{*}
-\bgroup
-\RaggedRight
-\printbibliography
-\egroup
+%\nocite{*}
+%\bgroup
+%\RaggedRight
+%\printbibliography
+%\egroup
\printindex
diff --git a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools.sty b/graphics/pstricks/contrib/pst-geometrictools/latex/pst-geometrictools.sty
index 2f1cd2e24c..2f1cd2e24c 100644
--- a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools.sty
+++ b/graphics/pstricks/contrib/pst-geometrictools/latex/pst-geometrictools.sty
diff --git a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.pdf b/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.pdf
deleted file mode 100644
index 39234a8145..0000000000
--- a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-doc.pdf
+++ /dev/null
Binary files differ
diff --git a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.pdf b/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.pdf
deleted file mode 100644
index 8b428e9601..0000000000
--- a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools-fr-doc.pdf
+++ /dev/null
Binary files differ
diff --git a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools.tex b/graphics/pstricks/contrib/pst-geometrictools/tex/pst-geometrictools.tex
index 7cd90ca17a..608e29ef56 100644
--- a/graphics/pstricks/contrib/pst-geometrictools/pst-geometrictools.tex
+++ b/graphics/pstricks/contrib/pst-geometrictools/tex/pst-geometrictools.tex
@@ -1,1233 +1,1238 @@
-%% This is file `pst-geometrictools.tex',
-%%
-%% Thomas Söll
-%%
-%% This program can redistributed and/or modified under %%
-%% the terms of the LaTeX Project Public License %%
-%% Distributed from CTAN archives in directory %%
-%% macros/latex/base/lppl.txt; either version 1.3c of %%
-%% the License, or (at your option) any later version. %%
-%%
-%% DESCRIPTION:
-%% `pst-geometrictools' is a PSTricks package to draw a protractor, a ruler, a compass and pencils
-%%
-%%
-\csname PSTgeometrictoolsLoaded\endcsname
-\let\PSTgeometrictoolsLoaded\endinput
-% Requires PSTricks, pst-xkey, pst-node packages
-\ifx\PSTricksLoaded\endinput\else\input pstricks.tex\fi
-\ifx\PSTXKeyLoaded\endinput\else\input pst-xkey.tex\fi
-\ifx\PSTnodeLoaded\endinput\else\input pst-node.tex\fi
-\def\fileversion{1.1}
-\def\filedate{2017/09/16}
-\message{`PST' v\fileversion, \filedate}
-
-\edef\PstAtCode{\the\catcode`\@} \catcode`\@=11\relax
-
-
-\pst@addfams{pst-geometrictools}
-
-\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ghost}[true]{}
-\define@key[psset]{pst-geometrictools}{ProLineCol}[cyan]{\pst@getcolor{#1}\ProLineCol}
-\define@key[psset]{pst-geometrictools}{ProFillCol}[gray!60]{\pst@getcolor{#1}\ProFillCol}
-\define@key[psset]{pst-geometrictools}{ProScale}[1]{\def\pst@ProScale{#1 }}%
-\define@key[psset]{pst-geometrictools}{OwnerTxt}[Euklid]{\def\pst@OwnerTxt{#1}}%
-\define@key[psset]{pst-geometrictools}{MadeTxt}[made in NES]{\def\pst@MadeTxt{#1}}%
-\define@key[psset]{pst-geometrictools}{PSfontO}[Symbol]{\def\pst@PSfontO{/#1 }}
-\define@key[psset]{pst-geometrictools}{fontsizeO}[10]{\def\pst@fontsizeO{#1 }}
-\define@key[psset]{pst-geometrictools}{PSfontM}[NimbusRomNo9L-Regu]{\def\pst@PSfontM{/#1 }}
-\define@key[psset]{pst-geometrictools}{fontsizeM}[6]{\def\pst@fontsizeM{#1 }}
-\define@key[psset]{pst-geometrictools}{country}[Germany]{\def\pst@country{#1}}
-\psset[pst-geometrictools]{ProScale=1,OwnerTxt={Euklid},MadeTxt={made in NES},
- country=Germany,PSfontO=StandardSymL,PSfontM=NimbusRomNo9L-Regu,fontsizeO=10,fontsizeM=6,
- ProFillCol=gray!60,ProLineCol=cyan,Ghost=false}
-
-
-\def\psProtractor{\def\pst@par{}\pst@object{psProtractor}}
-\def\psProtractor@i#1(#2){\@ifnextchar(%
-{\psProtractor@ii{#1}(#2)}%
-{\psProtractor@ii{#1}(#2)(#2)}}%
-\def\psProtractor@ii#1(#2)(#3){%------------------------------- #1 Winkel, #2 Ursprung P, zweiter Punkt Q für Winkel
-\begin@SpecialObj
-\pst@killglue
-\begingroup%
-\pnode(#2){@PGD}%
-\pnode(#3){@QGD}%
-\use@par%
-\pst@getcoor{@QGD}\pst@tempB % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempB
-\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
-\addto@pscode{%
-/sysfill {systemdict /fill get exec} def
-/Country (\pst@country) def
- /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
- \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
- \pst@tempB \tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
- @y1 @y2 sub @x1 @x2 sub Atan /@delta ED %------------ Winkelberechnung
- \pst@tempA \pst@coor T % ------------------------------------ Tranformiere den Koordinatenursprung in P
- @delta #1 add 180 add rotate % ------------------------------ Drehe das gesamte Geodreieck
- \pst@ProScale dup scale % -------- Skaliere das ganze Geodreieck
-%-------------------------------------------------------------------------------------------------------------
-\ifPst@Ghost\else
-gsave
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Äußere Begrenzung des Geodreiecks -----------------------------------------------
-gsave
- newpath
- -8 cm 0 moveto
- 16 cm 0 rlineto
- -8 cm 8 cm rlineto
- closepath
- gsave
- 0.7 setlinewidth
- 0.1 setgray
- stroke
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Gefüllter innerer Teil des Geodreiecks -----------------------------------------------
-gsave
- newpath
- -7.5 cm 0.5 22.5 tan mul cm moveto
- 15 cm 0 rlineto
- -7.5 cm 7.5 cm rlineto
- closepath
- gsave
- \pst@usecolor\ProFillCol
- [ /ca .1 /SetTransparency pdfmark % set transparency
- 0.1 .setopacityalpha sysfill
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Millimetereinteilung auf der Grundseite -------------------------------------------
- /mmBlinie { newpath
- -7 cm 0 cm moveto
- 0 cm 0.17 cm rlineto
-% closepath
- gsave
- 0.5 setlinewidth
- 0 setgray
- stroke
- grestore
- 0.1 cm 0 cm translate
- } def
-gsave
-140 {mmBlinie} repeat
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- 0,5- cm-Einteilung auf der Grundseite ----------------------------------------------
- /cmBlinie { newpath
- -7 cm 0 cm moveto
- 0 cm 0.27 cm rlineto
-% closepath
- gsave
- 0.55 setlinewidth
- 0 setgray
- stroke
- grestore
- 0.5 cm 0 cm translate
- } def
-gsave
- 29 {cmBlinie} repeat
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- mm-Einteilung von der Grundseite nach oben ------------------------------------
-/mmlinie { newpath
- -2.3 cm 0.3 cm moveto
- 0.2 cm 0 rlineto
- 2.2 cm 0.3 cm moveto
- 0.2 cm 0 rlineto
-% closepath
- gsave
- 0.5 setlinewidth
- 0 setgray
- stroke
- grestore
- 0 cm 0.1 cm translate
- } def
-gsave
-33 {mmlinie} repeat
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- 0,5 cm-Einteilung von der Grundseite nach oben --------------------------------
-/cmlinie { newpath
- -4.5 cm 0.5 cm moveto
- 2 cm 0 rlineto
- 0.75 cm 0 rmoveto
- 1.5 cm 0 rlineto
- 0.5 cm 0 rmoveto
- 1.5 cm 0 rlineto
- 0.75 cm 0 rmoveto
- 2 cm 0 rlineto
-% closepath
- gsave
- 0.6 setlinewidth
- 0 setgray
- stroke
- grestore
- 0 cm 0.5 cm translate
- } def
-%------------------------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- Clippen entlang eines Kreises der 0,5 cm-Einteilung von der Grundseite nach oben ------------------------------------
-/kreisring { newpath
- 0 0 translate
- 0 0 4.2 cm 0 180 arc
- closepath
- } def
- gsave
- kreisring clip
- 7 {cmlinie} repeat
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- farbiger und transparenter Halb-Ring -----------------------------------------------------------------------------
- gsave
- newpath
- 0 0 translate
- 0 0 5.1 cm 6 174 arc
- 0 0 4.8 cm 174 6 arcn
- closepath
- gsave
- \pst@usecolor\ProLineCol
- [ /ca .4 /SetTransparency pdfmark % set transparency
- 0.4 .setopacityalpha
- sysfill
- grestore
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 1-Grad-Winkeleinteilung an der linken Kathete -----------------------------------------------------------------
- gsave
- 91 1 179 { /Wk exch def % ---------------------------------------------------- Schleifenvariable festlegen, die von 91° bis 179° geht
- {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def %---------- xWS1=8/(tan(alpha)-1) --> SP der Geraden linke Kathete mit Ursprungsgeraden im Winkel alpha
- {7.8 Wk sin Wk cos div 1 sub div} /xWS2 exch def % ------- xWS2=7,8/(tan(alpha)-1) --> SP einer Parallelen zur Geraden linke Kathete mit Ursprungsgeraden im Winkel alpha
- newpath
- xWS1 cm xWS1 8 add cm moveto % --------------------------- zu xWS1 gehöriger y-Wert ist xWS1 + 8
- xWS2 cm xWS2 7.8 add cm % ----------------------------------- zu xWS2 gehöriger y-Wert ist xWS1 + 7,8
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 5-Grad-Winkeleinteilung an der linken Kathete -----------------------------------------------------------------
- gsave
- 95 5 175 { /Wk exch def
- {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def
- {7.6 Wk sin Wk cos div 1 sub div} /xWS2 exch def
- newpath
- xWS1 cm xWS1 8 add cm moveto
- xWS2 cm xWS2 7.6 add cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 10-Grad-Winkeleinteilung an der linken Kathete -----------------------------------------------------------------
- gsave
- 100 10 170 { /Wk exch def
- {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def
- {5.1 Wk cos mul Wk cos div 1 sub div} /xWS2 exch def
- newpath
- xWS1 cm xWS1 8 add cm moveto
- 5.1 Wk cos mul cm 5.1 Wk sin mul cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 1-Grad-Winkeleinteilung an der rechten Kathete ---------------------------------------------------------------
- gsave
- 1 1 89 { /Wk exch def
- {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
- {7.8 Wk sin Wk cos div 1 add div} /xWS2 exch def
- newpath
- xWS1 cm xWS1 neg 8 add cm moveto
- xWS2 cm xWS2 neg 7.8 add cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 5-Grad-Winkeleinteilung an der rechten Kathete ---------------------------------------------------------------
- gsave
- 5 5 85 { /Wk exch def
- {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
- {7.6 Wk sin Wk cos div 1 add div} /xWS2 exch def
- newpath
- xWS1 cm xWS1 neg 8 add cm moveto
- xWS2 cm xWS2 neg 7.6 add cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 10-Grad-Winkeleinteilung an der rechten Kathete --------------------------------------------------------------
- gsave
- 10 10 80 { /Wk exch def
- {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
- {5.1 Wk cos mul Wk cos div 1 add div} /xWS2 exch def
- newpath
- xWS1 cm xWS1 neg 8 add cm moveto
- 5.1 Wk cos mul cm 5.1 Wk sin mul cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 1-Grad-Winkeleinteilung auf Halbkreis ------------ ---------------------------------------------------------------
- gsave
- 5 1 175 { /Wk exch def
- newpath
- 4.3 Wk cos mul cm 4.3 Wk sin mul cm moveto
- 4.45 Wk cos mul cm 4.45 Wk sin mul cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- 5-Grad-Winkeleinteilung auf Halbkreis ------------ ---------------------------------------------------------------
- gsave
- 5 5 175 { /Wk exch def
- newpath
- 4.3 Wk cos mul cm 4.3 Wk sin mul cm moveto
- 4.5 Wk cos mul cm 4.5 Wk sin mul cm
- lineto
-% closepath
- 0.5 setlinewidth
- 0 setgray
- stroke
- } for
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%-------------------------- Linke Diagonallinie-dashed -------------------------------------------------------------------------------
- gsave
- newpath /Wk 135 def
- {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def
- 0 0 moveto
- 4.3 Wk cos mul cm 4.3 Wk sin mul cm lineto
-% closepath
- gsave
- [2 sqrt 2 div 0.24 sub cm 0.24 cm] -0.12 cm setdash
- 0.5 setlinewidth
- 0 setgray stroke
- grestore
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%-------------------------- Rechte Diagonallinie-dashed -----------------------------------------------------------------------------
- gsave
- newpath /Wk 45 def
- {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
- 0 0 moveto
- 4.3 Wk cos mul cm 4.3 Wk sin mul cm lineto
-% closepath
- gsave
- [2 sqrt 2 div 0.24 sub cm 0.24 cm] -0.12 cm setdash
- 0.5 setlinewidth
- 0 setgray stroke
- grestore
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------
-%---------------------------------------- Mittel-Linie -------------------------------------------------------------------------------------
- gsave
- newpath
- 0 0.5 cm moveto
- 0 3.5 cm lineto
- 0 5.1 cm moveto
- 0 6.0 cm lineto
- 0 6.4 cm moveto
- 0 8.0 cm lineto
-% closepath
- gsave
- 0.5 setlinewidth
- 0 setgray stroke
- grestore
- grestore
-%--------------------------------------------------------------------------------------------------------------------------------------------------
-%------------------------- Definition für horizontal-zentriertes - Setzen der cm- Zahlen (180° gedreht) ------------------------
- /cmshow {% (string) x y
- gsave
- moveto 180 rotate % s
- /NimbusRomNo9L-Regu findfont 7 scalefont setfont
- dup % s s
- stringwidth pop 2 div neg 0 % s -dx/2
- rmoveto 0.2 setgray show
- grestore
- } bind def
-%------------------------- Setzen der Zahlen für die cm-Einteilungen -----------------------------------------------------------------
- 0 1 7 { /MZ exch def MZ 2 string cvs MZ cm 0.47 cm cmshow } for %---------------- Zahlen 0 bis 7 (nach rechts)
- 1 1 7 { /MZ exch def MZ 2 string cvs MZ neg cm 0.47 cm cmshow } for %----------- Zahlen 1 bis 7 (nach links)
- 1 1 3 { /MZ exch def MZ 2 string cvs 2 cm MZ 0.1 add cm cmshow } for %---------- Zahlen 1 bis 3 (nach oben, rechte Seite)
- 1 1 3 { /MZ exch def MZ 2 string cvs -2 cm MZ 0.1 add cm cmshow } for %--------- Zahlen 1 bis 3 (nach oben, linke Seite)
-%--------------------------------------------------------------------------------------------------------------------------------------------------
-%------------------------- Definition für horizontal-zentriertes - Setzen der Winkel- Zahlen (mitgedreht) ----------------------
- /cmRotshow {% ---------------------------------- (string), Winkel, x y
- gsave
- moveto 90 add rotate % s
- /NimbusRomNo9L-Regu findfont 7 scalefont setfont
- dup % s s
- stringwidth pop 2 div neg 0 % s -dx/2
- rmoveto 0.2 setgray show
- grestore
- } bind def
- gsave
-%------------------------- Setzen der Zahlen für die Winkel-Einteilungen -------------------------------------------------------------------------------------------------
- 10 10 170 { /MZ exch def MZ 3 string cvs MZ 5.03 cm MZ cos mul 5.03 cm MZ sin mul cmRotshow } for % ------------------ äußerer Kreisbogen
- 10 10 170 { /MZ exch def 180 MZ sub 3 string cvs MZ 4.75 cm MZ cos mul 4.75 cm MZ sin mul cmRotshow } for % ------- innerer Kreisbogen
- grestore
-%---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /TSshow {% (string) x y
- gsave
- moveto 180 rotate % s
- \pst@PSfontO\space findfont \pst@fontsizeO scalefont setfont
- dup % s s
- stringwidth pop 2 div neg 0 % s -dx/2
- rmoveto 0.4 setgray show
- grestore
- } bind def
- gsave
- (\pst@OwnerTxt) 0 cm 4 cm TSshow
- grestore
-%--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
- /MadeShow {% (string) x y
- gsave
- moveto 180 rotate % s
- \pst@PSfontM\space findfont \pst@fontsizeM scalefont setfont
- dup % s s
- stringwidth pop 2 div neg 0 % s -dx/2
- rmoveto 0.7 setgray show
- grestore
- } bind def
- gsave
- (\pst@MadeTxt) 0 cm 6.25 cm MadeShow
- grestore
-%---------------------------------------- Fahne -------------------------------------------------------------------------------------
- gsave
- /Fahne {
- newpath
- 0 0 moveto
- 0 1 rlineto
- 1 0 rlineto
- 0 -1 rlineto
- closepath
- setrgbcolor
- [ /ca .5 /SetTransparency pdfmark % set transparency
- 0.5 .setopacityalpha sysfill
- } def
-Country (France) eq {
- 0.73 cm 6.1 cm translate
- 3 6 scale
- 1 0 0 Fahne
- 1 0 translate
- 1 1 1 Fahne
- 1 0 translate
- 0 0 1 Fahne
- } if
-Country (Germany) eq {
- 0.775 cm 6.22 cm translate
- 7.5 1.5 scale
- 1 0.588 0 Fahne
- 0 -1 translate
- 0.75 0.07 0.11 Fahne
- 0 -1 translate
- 0 0 0 Fahne
- } if
- grestore
-%--------------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- Ende nur grestore von gsave ganz am Anfang ------------------
-grestore
-\fi
-}%
-\pnode(!
- /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
- \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
- \pst@tempB \tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
- @y1 @y2 sub @x1 @x2 sub Atan /@delta ED %------------ Winkelberechnung
- @x1 cm @y1 cm T % ------------------------------------ Tranformiere den Koordinatenursprung in P
- @delta #1 add 180 add rotate % ------------------------------ Drehe den oberen Punkt des Geodreiecks
- \pst@ProScale\space \pst@ProScale\space scale % -------- Skalieren!
- 0 8){GeodrC}%
-\pnode(!
- @x1 cm @y1 cm T % ------------------------------------ Tranformiere den Koordinatenursprung in P
- @delta #1 add 180 add rotate % ------------------------------ Drehe die linke untere Ecke des Geodreiecks
- \pst@ProScale\space \pst@ProScale\space scale % -------- Skalieren!
- -8 0){GeodrA}%
-\pnode(!
- @x1 cm @y1 cm T % ------------------------------------ Tranformiere den Koordinatenursprung in P
- @delta #1 add 180 add rotate % ------------------------------ Drehe die rechte untere Ecke des Geodreiecks
- \pst@ProScale\space \pst@ProScale\space scale % -------- Skalieren!
- 8 0){GeodrB}%
-\endgroup%
-\end@SpecialObj\ignorespaces
-}%
-
-
-\definecolor{HolzCol}{rgb}{1,0.937,0.835}%
-\define@key[psset]{pst-geometrictools}{PenScale}[1]{\def\pst@PenScale{#1 }}%
-\define@key[psset]{pst-geometrictools}{PenLength}[5]{\def\pst@PenLength{#1 }}%
-\define@key[psset]{pst-geometrictools}{pencilColA}[red]{\pst@getcolor{#1}\pencilColA}
-\define@key[psset]{pst-geometrictools}{pencilColB}[HolzCol]{\pst@getcolor{#1}\pencilColB}
-\psset[pst-geometrictools]{PenLength=5,pencilColA=red,pencilColB=HolzCol,PenScale=1}
-\def\psPencil{\def\pst@par{}\pst@object{psPencil}}
-\def\psPencil@i#1(#2){%------------------------------- #1 Winkel, #2 Ursprung P
-\begin@SpecialObj
-\pst@killglue
-\begingroup
-\pnode(#2){@PGD}%
-\use@par
-\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
-\addto@pscode{
-/sysfill {systemdict /fill get exec} def
-%/Country (\pst@country) def
- /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
- /Plength \pst@PenLength def
-% \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
- \pst@tempA \pst@coor T % ------------------------------------ Tranformiere den Koordinatenursprung in P
- #1 rotate % ------------------------------ Drehe das gesamte Geodreieck
- \pst@PenScale dup scale % -------- Skaliere das ganze Geodreieck
-%-------------------------------------------------------------------------------------------------------------
-gsave
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Unterer Holzteil des Stifts -------------------------------------------------------------
-gsave
- newpath
- 0 cm 0 moveto
- -0.3 cm 1 cm rlineto
- 0 cm 0.2 cm rlineto
- 0.6 cm 0 cm rlineto
- 0 cm -0.2 cm rlineto
- closepath
- gsave
- \pst@usecolor\pencilColB
- fill
- grestore
- gsave
- 0.4 setlinewidth
- 0.5 setgray
- 1 setlinejoin
- stroke
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- langer farbiger Teil des Stifts ----------------------------------------------------------
-gsave
- newpath
- -0.3 cm 1 cm moveto
- 0 cm Plength cm rlineto
- 0.6 cm 0 cm rlineto
- 0 cm Plength neg cm rlineto
- 0.3 cm 1.13 cm 0.13 cm 270 180 arcn
- 0 cm 1.13 cm 0.17 cm 0 180 arcn
- -0.3 cm 1.13 cm 0.13 cm 0 270 arcn
- closepath
- gsave
- \pst@usecolor\pencilColA
- fill
- grestore
- gsave
- 0.5 setlinewidth
- 0.1 setgray
- stroke
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%--------------------------- Spitze in Farbe --------------------------------------------------------------
-gsave
- newpath
- 0 cm 0 moveto
- -0.1 cm 1 3 div cm rlineto
- 0.2 cm 0 cm rlineto
- closepath
- gsave
- \pst@usecolor\pencilColA
- fill
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%--------------------------- Striche im Stift --------------------------------------------------------------
-gsave
- newpath
- -0.17 cm 1.13 cm moveto
- 0 cm Plength 0.13 sub cm rlineto
- 0.17 cm 1.13 cm moveto
- 0 cm Plength 0.13 sub cm rlineto
- closepath
- gsave
- 0.5 setlinewidth
- 0.1 setgray
- stroke
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%--------------------------- Elliptisches Stift-Ende in Holz --------------------------------------------
-gsave
- newpath
- 0 cm Plength 1 add cm T
- 1 0.2 scale
- 0 cm 0 cm 0.3 cm 0 360 arc
- closepath
- gsave
- \pst@usecolor\pencilColB
- fill
- grestore
- gsave
- 0.5 setlinewidth
- 0.3 setgray
- stroke
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%--------------------------- Elliptisches Stift-Ende in Farbe -------------------------------------------
-gsave
- newpath
- 0 cm Plength 1 add cm T
- 1 0.2 scale
- 0 cm 0 cm 0.1 cm 0 360 arc
- closepath
- gsave
- \pst@usecolor\pencilColA
- fill
- grestore
- gsave
- 0.3 setlinewidth
- 0.3 setgray
- stroke
- grestore
-grestore
-%--------------------------------------------------------------------------------------------------------
-%--------------------------------------------------------------------------------------------------------
-grestore
-}%
-\endgroup
-\end@SpecialObj\ignorespaces
-}%
-
-
-\define@key[psset]{pst-geometrictools}{RulerFillCol}[cyan!60]{\pst@getcolor{#1}\RulerFillCol}
-\define@key[psset]{pst-geometrictools}{RulerScale}[1]{\def\pst@RulerScale{#1 }}%
-\psset[pst-geometrictools]{RulerFillCol=gray,RulerScale=1}
-
-\def\psRuler{\def\pst@par{}\pst@object{psRuler}}
-\def\psRuler@i#1(#2){\@ifnextchar(%
-{\psRuler@ii{#1}(#2)}%
-{\psRuler@ii{#1}(#2)(#2)}}%
-\def\psRuler@ii#1(#2)(#3){%------------------------------- #1 Winkel, #2 Ursprung P, zweiter Punkt Q für Winkel
-\begin@SpecialObj
-\pst@killglue
-\begingroup%
-\pnode(#2){@PGD}%
-\pnode(#3){@QGD}%
-\use@par%
-\pst@getcoor{@QGD}\pst@tempB % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempB
-\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
-\addto@pscode{
-/sysfill {systemdict /fill get exec} def
- /cm {28.45274 mul} def % --------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
- \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
- \pst@tempB \tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
- @y1 @y2 sub @x1 @x2 sub Atan /@delta ED %------------ Winkelberechnung
- \pst@tempA \pst@coor T % ------------------------------------ Tranformiere den Koordinatenursprung in P
- @delta #1 add 180 add rotate % ------------------------------ Drehe das gesamte Geodreieck
- \pst@RulerScale dup scale % ----------------------------------- Skaliere das ganze Geodreieck
-%-------------------------------------------------------------------------------------------------------------
-gsave
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Füllung der beiden inneren Bereiche und äußere Begrenzung des Lineals -----------------------------------------------
-gsave
- newpath
- -0.2 cm 0 moveto
- 30.4 cm 0 rlineto
- 0 cm -0.9 cm rlineto
- -30.4 cm 0 cm rlineto
- closepath
- gsave
- \pst@usecolor\RulerFillCol
- [ /ca .25 /SetTransparency pdfmark % set transparency
- 0.25 .setopacityalpha sysfill
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-gsave
- newpath
- -0.2 cm 0 moveto
- 30.2 cm 0 lineto
- 0 cm -3 cm rlineto
- -30.4 cm 0 cm rlineto
- closepath
- 3.75 cm -1.5 cm moveto
- 3.5 cm -1.5 cm 0.25 cm 0 360 arc
- closepath
- gsave
- \pst@usecolor\RulerFillCol
- [ /ca .15 /SetTransparency pdfmark % set transparency
- 0.15 .setopacityalpha sysfill
- grestore
- gsave
-% 2 setlinejoin
- 0.7 setlinewidth
- 0.1 setgray
- stroke
- grestore
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Millimetereinteilung auf der Grundseite -------------------------------------------
- /mmBlinie { newpath
- 0 cm 0 cm moveto
- 0 cm -0.25 cm rlineto
- gsave
- 0.5 setlinewidth
- 0 setgray
- stroke
- grestore
- 0.1 cm 0 cm translate
- } def
-gsave
-300 {mmBlinie} repeat
-grestore
-%-------------------------------------------------------------------------------------------------------------
-%-------------- 0,5- cm-Einteilung auf der Grundseite ----------------------------------------------
- /cmBlinie { newpath
- 0.5 cm 0 cm moveto
- 0 cm -0.375 cm rlineto
-% closepath
- gsave
- 0.55 setlinewidth
- 0 setgray
- stroke
- grestore
- 1 cm 0 cm translate
- } def
-gsave
- 30 {cmBlinie} repeat
-grestore
-%-------------- 1- cm-Einteilung auf der Grundseite ----------------------------------------------
- /cmBlinie { newpath
- 0 cm 0 cm moveto
- 0 cm -0.5 cm rlineto
-% closepath
- gsave
- 0.6 setlinewidth
- 0 setgray
- stroke
- grestore
- 1 cm 0 cm translate
- } def
-gsave
- 31 {cmBlinie} repeat
-grestore
-%--------------------------------------------------------------------------------------------------------------------------------------------------
-%------------------------- Definition für horizontal-zentriertes - Setzen der cm- Zahlen (180° gedreht) ------------------------
- /cmshow {% (string) x y
- gsave
- moveto % s
- /NimbusRomNo9L-Regu findfont 8 scalefont setfont
- dup % s s
- stringwidth pop 2 div neg 0 % s -dx/2
- rmoveto 0.2 setgray show
- grestore
- } bind def
-%------------------------- Setzen der Zahlen für die cm-Einteilungen -----------------------------------------------------------------
- 0 1 30 { /MZ exch def MZ 2 string cvs MZ cm -0.78 cm cmshow } for %---------------- Zahlen 0 bis 30 (nach rechts)
-%-------------------------------------------------------------------------------------------------------------
-%--------------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- Ende nur grestore von gsave ganz am Anfang ------------------
-grestore
-}%
-\endgroup%
-\end@SpecialObj\ignorespaces
-}%
-
-\definecolor{PoCRed}{rgb}{0.7,0.134,0.134}
-\define@boolkey[psset]{pst-geometrictools}[Pst@]{MCAngle}[true]{}
-\define@key[psset]{pst-geometrictools}{PoCLength}[5]{\def\pst@PoCLength{#1 }}
-\define@key[psset]{pst-geometrictools}{PoCAngle}[0]{\def\pst@PoCAngle{#1 }}
-\define@key[psset]{pst-geometrictools}{PoCFillCol}[PoCRed]{\pst@getcolor{#1}\PoCFillCol}
-\define@key[psset]{pst-geometrictools}{PoCMineCol}[black!80]{\pst@getcolor{#1}\PoCMineCol}
-\define@key[psset]{pst-geometrictools}{PoCScale}[1]{\def\pst@PoCScale{#1 }}%
-\define@key[psset]{pst-geometrictools}{RadVS}[RVS]{\def\pst@RadVS{#1}}%
-\define@key[psset]{pst-geometrictools}{AngleVS}[AVS]{\def\pst@AngleVS{#1}}%
-\define@key[psset]{pst-geometrictools}{RadMul}[1]{\def\pst@RadMul{#1 }}%
-\psset[pst-geometrictools]{PoCScale=1,PoCFillCol=PoCRed,PoCAngle=0,PoCMineCol=black!80,PoCLength=5,MCAngle=true,RadVS=RVS,AngleVS=AVS,RadMul=1}
-
-\def\psCompass{\def\pst@par{}\pst@object{psCompass}}% Pair of Compasses
-\def\psCompass@i#1(#2){\@ifnextchar(%
-{\psCompass@ii{0}(#2)}%
-{\psCompass@ii{#1}(#2)(#2)}}%
-\def\psCompass@ii#1(#2)(#3){%------------------------------- #1 Winkel, #2 Ursprung P, zweiter Punkt Q für Winkel
-\begin@SpecialObj
-\pst@killglue
-\begingroup%
-\pnode(#2){@PGD}%
-\pnode(#3){@QGD}%
-\use@par%
-\pst@getcoor{@QGD}\pst@tempB % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempB
-\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
-\addto@pscode{%
- \pst@RadMul /faktor ED
- \pst@PoCScale /skal ED
- #1 skal div 2 div /Radius ED
- skal dup scale % -------- Skaliere das ganze Geodreieck
- /sysfill {systemdict /fill get exec} def
- /SLg \pst@PoCLength def
- /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
- \pst@tempA\tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
- \pst@tempB\tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
- \pst@tempA\pst@coor /@y3 ED /@x3 ED
- @y1 @y2 sub dup mul @x1 @x2 sub dup mul add faktor dup mul mul /quadlg ED
- quadlg 0 eq { 180 } { @y1 @y2 sub @x1 @x2 sub atan } ifelse /@delta ED %------------ Winkelberechnung
- quadlg sqrt 2 div /RadiusPktB ED %------------ Radiusberechnung mit zweitem Punkt
- SLg RadiusPktB Radius add gt { RadiusPktB Radius add } { SLg } ifelse /RadPoC ED
- /hoehe SLg dup mul RadPoC dup mul sub sqrt def
- /phiS RadPoC hoehe atan def
- @x3 @y3 T % ------------------------------------------------------------------------------- Transformiere den Koordinatenursprung in P
- \pst@PoCAngle\space \ifPst@MCAngle\space @delta add 180 add \fi rotate % ------------------------------ Drehe das gesamte Geodreieck
-%-------------------------------------------------------------------------------------------------------------
-gsave
-%-------------------------------------------------------------------------------------------------------------
-%-------------- Linke Zirkelspitze----------------------------------------------- 0 cm 0 cm 0.15 cm 0 360 arc
-gsave
- newpath
- phiS neg rotate
- 0 cm 0 cm moveto
- -0.1 cm 0.33 cm lineto
- 0.07 cm 0 cm rlineto
- closepath
- gsave
- 0.5 setgray
- fill
- grestore
-grestore
-%---------------------------------------- rechte Zirkel-Mine --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm T
- phiS 2 mul rotate
- 0 cm SLg neg cm moveto
- 0.06 cm 0.1 cm rlineto
- 0.013 cm 0.2 cm rlineto
- -0.06 cm 0 cm rlineto
- closepath
- gsave
- \pst@usecolor\PoCMineCol
- fill
- grestore
-grestore
-%---------------------------------------- Spindel --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- -2 cm -1 phiS cos mul cm rmoveto
- 4 cm 0 cm rlineto
- gsave
- 0.5 setgray
- 1.6 setlinewidth
- stroke
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- -2 cm -1 phiS cos mul cm rmoveto
- 0.2 -0.75 rmoveto
- 189 { 0.5 1.5 rlineto
- 0.1 -1.5 rmoveto } repeat
- gsave
- 0.2 setgray
- 0.2 setlinewidth
- stroke
- grestore
-grestore
-%---------------------------------------- Drehrad an der Spindel --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- 0 cm -1.3 phiS cos mul cm rmoveto
- 0 cm 0.6 cm rlineto
- gsave
- 0.5 setgray
- 0.08 cm setlinewidth
- stroke
- grestore
-grestore
-gsave
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- -0.04 cm -1.28 phiS cos mul cm rmoveto
- 20 { 0.08 cm 0 cm rlineto
- -0.08 cm 0.03 cm rmoveto } repeat
- gsave
- 0.3 setgray
- 0.2 setlinewidth
- stroke
- grestore
-grestore
-gsave
-%---------------------------------------- Halterung zum Anfassen --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- 0 cm 0.75 0.54 phiS sin mul add cm moveto
- 0 cm 0.2 cm rlineto
- gsave
- 0.5 setgray
- 3 setlinewidth
- stroke
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- 0 cm 0.95 0.54 phiS sin mul add cm moveto
- 0 cm 0.05 cm rlineto
- gsave
- \pst@usecolor\PoCFillCol
- 5 setlinewidth
- stroke
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- 0 cm 1.0 0.54 phiS sin mul add cm moveto
- 0 cm 0.5 cm rlineto
- gsave
- 0.5 setgray
- 5 setlinewidth
- stroke
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- -0.08 cm 1.0 0.6 phiS sin mul add cm moveto
- 0 cm 0.48 cm rlineto
- 6 { 0.025 cm -0.48 cm rmoveto
- 0 cm 0.48 cm rlineto } repeat
- gsave
- 0.65 setgray
- 0.15 setlinewidth
- stroke
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- -0.075 cm 1.0 0.6 phiS sin mul add cm moveto
- 0 cm 0.48 cm rlineto
- 6 { 0.025 cm -0.48 cm rmoveto
- 0 cm 0.48 cm rlineto } repeat
- gsave
- 0.25 setgray
- 0.2 setlinewidth
- stroke
- grestore
-grestore
-%---------------------------------------- Kreis um oberen Teil --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm T
- phiS rotate
- 0 cm 0.1 0.54 phiS sin mul add cm moveto
- 0.65 -50 PtoC exch cm exch cm rmoveto
- 0 cm 0.1 0.54 phiS sin mul add cm 0.65 cm -50 230 arc
- gsave
- 0.1 setgray
- 1.3 setlinewidth
- stroke
- grestore
-grestore
-%---------------------------------------- Kreis zwischen den Schenkeln --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm moveto
- 0 cm SLg cm 0.15 cm 0 360 arc
- closepath
- gsave
- 0.1 setgray
- fill
- grestore
-grestore
-%---------------------------------------- Schenkel des Zirkels ----------------------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm 0.3 cm moveto
- -0.3 cm SLg 0.1 add cm lineto
- 0 cm SLg cm T
- phiS 2 mul rotate
- 0.3 cm 0.1 cm moveto
- 0 cm SLg 0.3 sub neg cm lineto
-% closepath
- gsave
- 0.285 cm setlinewidth
- 2 setlinejoin
- \pst@usecolor\PoCFillCol
- stroke
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- -0.17 cm SLg 0.6 mul cm moveto
- -0.25 cm SLg 0.85 mul cm lineto
- 0 cm SLg cm T
- phiS 2 mul rotate
- 0.17 cm SLg -0.4 mul cm moveto
- 0.25 cm SLg -0.15 mul cm lineto
-% closepath
- gsave
- 0.17 cm setlinewidth
- 2 setlinejoin
- 0.4 setgray
- stroke
- grestore
-grestore
-%---------------------------------------- Kreis an der linken Spitze --------------------------------------
-gsave
- newpath
- phiS neg rotate
- -0.03 cm 0.8 cm moveto
- -0.03 cm 0.8 cm 0.175 cm 0 360 arc
- closepath
- gsave
- 0.25 setgray
- fill
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- -0.03 cm 0.8 cm moveto
- -0.03 cm 0.8 cm 0.025 cm 0 360 arc
- closepath
- gsave
- 0.8 setgray
- fill
- grestore
-grestore
-%---------------------------------------- Kreis an der rechten Spitze --------------------------------------
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm T
- phiS 2 mul rotate
- 0.03 cm 0 cm T
- 0 cm SLg 0.8 sub neg cm moveto
- 0 cm SLg 0.8 sub cm neg 0.175 cm 0 360 arc
- closepath
- gsave
- 0.25 setgray
- fill
- grestore
-grestore
-gsave
- newpath
- phiS neg rotate
- 0 cm SLg cm T
- phiS 2 mul rotate
- 0.03 cm 0 cm T
- 0 cm SLg 0.8 sub neg cm moveto
- 0 cm SLg 0.8 sub cm neg 0.025 cm 0 360 arc
- closepath
- gsave
- 0.8 setgray
- fill
- grestore
-grestore
-%--------------------------------------------------------------------------------------------------------------------------------------------------
-%--------------- Ende nur grestore von gsave ganz am Anfang ------------------
-grestore
-}%
-\pnode(!
- \pst@tempA \tx@UserCoor /@@y1 ED /@@x1 ED
- \pst@tempB \tx@UserCoor /@@y2 ED /@@x2 ED
- @@x1 @@x2 sub @@y1 @@y2 sub Pyth \pst@RadMul\space mul /\pst@RadVS\space exch def
- @@y1 @@y2 sub dup mul @@x1 @@x2 sub dup mul add \pst@RadMul dup mul mul /quadlg ED
- quadlg 0 eq { 180 } { @@y1 @@y2 sub @@x1 @@x2 sub atan } ifelse /\pst@AngleVS\space exch def %------------ Winkelberechnung /\pst@AngleVS\space exch def
- 0 0){MoneyforNothing}%
-\endgroup%
-\end@SpecialObj\ignorespaces%
-}%
-
-%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ruler}[true]{}
-%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ppoint}[false]{}
-%\define@boolkey[psset]{pst-geometrictools}[Pst@]{LineOffset}[false]{}
-%\define@key[psset]{pst-geometrictools}{AddAngle}[0]{\def\pst@AddAngle{#1 }}%
-%\psset[pst-geometrictools]{Ruler=true,Ppoint=false,AddAngle=0,LineOffset=false}
-
-%% Distance between two points => #3
-\def\psDistAB(#1)(#2)#3{%
- \pst@getcoor{#1}\pst@tempA
- \pst@getcoor{#2}\pst@tempB
-\pnode(!
- \pst@tempA \tx@UserCoor
- \pst@tempB \tx@UserCoor
- 3 -1 roll sub dup mul 3 1 roll sub dup mul add sqrt
- /#3 ED
- 0 0
- ){XX}
-}
-%% calcule l'angle entre Ox et AB et le place en #3
-\def\psAngleAB(#1)(#2)#3{%
- \pst@getcoor{#1}\pst@tempA
- \pst@getcoor{#2}\pst@tempB
-\pnode(!
- \pst@tempA \tx@UserCoor
- \pst@tempB \tx@UserCoor
- 3 -1 roll sub 3 1 roll exch sub Atan
- /#3 ED
- 0 0
- ){YY}
-}%
-%% angle defined by three points
-\def\psAngleAOB(#1)(#2)(#3)#4{%
- \pst@getcoor{#1}\pst@tempA
- \pst@getcoor{#2}\pst@tempB
- \pst@getcoor{#2}\pst@tempC
-\pnode(!
- \pst@tempA \tx@UserCoor
- \pst@tempB \tx@UserCoor
- \pst@tempC \tx@UserCoor
- 4 copy exch 4 -1 roll mul
- 3 -2 roll mul add
- 4 -2 roll mul 4 -2 roll mul sub exch Atan
- /#4 ED
- 0 0
- ){ZZ}
-}
-
-% la nouvelle version de \psParallels
-\define@key[psset]{pst-geometrictools}{DistCoeff}[1]{\def\pst@DistCoeff{#1 }}%
-\psset[pst-geometrictools]{DistCoeff=1}
-%
-\def\psParallels{\def\pst@par{}\pst@object{psParallels}}
-\def\psParallels@i(#1)(#2)(#3){%
-\begin@SpecialObj %
-\pnode(#1){pointA}%
-\pnode(#2){pointB}%
-\pnode(#3){pointC}%
-\pcline[nodesep=-3](pointA)(pointB)
-\psdots(pointA)(pointB)(pointC)
-\uput[l](pointA){A}
-\uput[l](pointB){B}
-\uput[r](pointC){C}
-%
-\psProtractor[Ghost]{0}(pointA)%
-\psAngleAB(pointA)(pointB){alpha1}
-\psAngleAB(pointA)(GeodrA){alpha2}
-\psProtractor[Ghost]{alpha1 alpha2 sub}(pointA)%
-\psRuler{0}(GeodrB)(GeodrC)
-%
-\pstProjection[PointName={},PointSymbol=none]{pointA}{pointB}{pointC}[pointI]%
-\pstRotation[RotAngle=45,PointSymbol=none,PointName={}]{pointC}{pointI}[pointJ]%
-\pstInterLL[PointSymbol=none,PointName={}]{pointA}{pointB}{pointC}{pointJ}{pointK}%
-\pstTranslation[PointSymbol=none,PointName={},DistCoef=\pst@DistCoeff]{pointK}{pointC}{pointA}[pointA*]
-\psProtractor{alpha1 alpha2 sub}(pointA*)%
-\end@SpecialObj\ignorespaces%
-}%
-
-%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ruler}[true]{}
-%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ppoint}[false]{}
-%\define@boolkey[psset]{pst-geometrictools}[Pst@]{LineOffset}[false]{}
-%\define@key[psset]{pst-geometrictools}{AddAngle}[1]{\def\pst@AddAngle{#1 }}%
-%\psset[pst-geometrictools]{Ruler=true,Ppoint=false,AddAngle=0,LineOffset=false}
-%\def\psParallels{\def\pst@par{}\pst@object{psParallels}}
-%\def\psParallels@i(#1)(#2)(#3){%
-%\psset{saveNodeCoors,NodeCoorPrefix=n}%
-%\@ifundefined{rCounter}{\def\rCounter{1}}{}%
-%\begin@SpecialObj %
-%\pnode(#1){pointA}%
-%\pnode(#2){pointB}%
-%\pnode(#3){pointC}%
-%\pstProjection[PointName={},PointSymbol=none]{pointA}{pointB}{pointC}[pointI]%
-%\midAB(pointA)(pointB){pointM}%
-%\pstRotation[RotAngle=45,PointSymbol=none,PointName={}]{pointC}{pointI}[pointJ]%
-%\pstInterLL[PointSymbol=none,PointName={}]{pointA}{pointB}{pointC}{pointJ}{pointK}%
-%\AtoB(pointI)(pointC){IC}%
-%\AtoB(pointK)(pointC){KC}%
-%\AplusB(pointM)(KC){MT}%
-%\AplusB(pointB)(KC){BT}%
-%\psProtractor[Ghost]{0}(pointM)(pointB)%
-%\pnode(GeodrB){ProB}%
-%\pnode(GeodrC){ProC}%
-%\psLDNode(ProB)(ProC){-1cm}{pointE}%
-%\ifPst@Ruler\psRuler{0}(pointE)(GeodrC)\fi%
-%\AplusB(ProB)(KC){ProB*}%
-%\pst@Verb{ nKCx nKCy Pyth /laenge exch def %
-%nKCx laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delX exch def %
-%nKCy laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delY exch def
-%}%
-%\pnode(!nProB*x delX add nProB*y delY add ){GProB*}%
-%\pnode(!/AddA \pst@AddAngle def nProB*x AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse nProB*y AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){GProBC*}%
-%\pnode(!nMTx delX add nMTy delY add){GMT*}%
-%\pnode(!/AddA \pst@AddAngle def npointCx AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse npointCy AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){pointC*}%
-%\psLNode(pointM)(GMT*){\rCounter}{MPro}%
-%\psLNode(ProB)(GProB*){\rCounter}{BPro}%
-%\ifPst@Ppoint
-%\ifPst@LineOffset
-%\pst@Verb{ nICx nICy Pyth /laenge exch def %
-%nICx laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delX exch def %
-%nICy laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delY exch def %
-%}%
-%\pnode(!/AddA \pst@AddAngle def nProB*x AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse nProB*y AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){GProBC*}%
-%\pnode(!/AddA \pst@AddAngle def npointCx AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse npointCy AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){pointC*}%
-%\psProtractor{\pst@AddAngle}(pointC*)(GProBC*)\else%
-%\psProtractor{\pst@AddAngle}(pointC)(ProB*)\fi%
-%\else
-%\psProtractor{\pst@AddAngle}(MPro)(BPro)\fi % Um die Liniendicke 0.8pt nach rechts versetzt
-%\psLNode(pointC)(ProB*){0.98}{ProB**}%
-%\psLNode(pointC)(ProB**){2}{C*}%
-%\end@SpecialObj\ignorespaces%
-%}%
-
-\catcode`\@=\PstAtCode\relax
+%% This is file `pst-geometrictools.tex',
+%%
+%% Thomas Söll
+%% fixes for lualatex by Herbert Voß
+%%
+%% This program can redistributed and/or modified under %%
+%% the terms of the LaTeX Project Public License %%
+%% Distributed from CTAN archives in directory %%
+%% macros/latex/base/lppl.txt; either version 1.3c of %%
+%% the License, or (at your option) any later version. %%
+%%
+%% DESCRIPTION:
+%% `pst-geometrictools' is a PSTricks package to draw a protractor, a ruler, a compass and pencils
+%%
+%%
+\csname PSTgeometrictoolsLoaded\endcsname
+\let\PSTgeometrictoolsLoaded\endinput
+% Requires PSTricks, pst-xkey, pst-node packages
+\ifx\PSTricksLoaded\endinput \else\input pstricks.tex\fi
+\ifx\PSTXKeyLoaded\endinput \else\input pst-xkey.tex\fi
+\ifx\PSTEuclideLoaded\endinput\else\input pst-eucl.tex\fi
+\ifx\PSTnodeLoaded\endinput \else\input pst-node.tex\fi
+\def\fileversion{1.3}
+\def\filedate{2021/12/28}
+\message{`PST' v\fileversion, \filedate}
+
+\edef\PstAtCode{\the\catcode`\@} \catcode`\@=11\relax
+\pst@addfams{pst-geometrictools}
+%
+\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ghost}[true]{}
+\define@key[psset]{pst-geometrictools}{ProLineCol}[cyan]{\pst@getcolor{#1}\ProLineCol}
+\define@key[psset]{pst-geometrictools}{ProFillCol}[gray!60]{\pst@getcolor{#1}\ProFillCol}
+\define@key[psset]{pst-geometrictools}{ProScale}[1]{\def\pst@ProScale{#1 }}%
+\define@key[psset]{pst-geometrictools}{OwnerTxt}[Euklid]{\def\pst@OwnerTxt{#1}}%
+\define@key[psset]{pst-geometrictools}{MadeTxt}[made in NES]{\def\pst@MadeTxt{#1}}%
+\define@key[psset]{pst-geometrictools}{PSfontO}[Symbol]{\def\pst@PSfontO{/#1 }}
+\define@key[psset]{pst-geometrictools}{fontsizeO}[10]{\def\pst@fontsizeO{#1 }}
+\define@key[psset]{pst-geometrictools}{PSfontM}[NimbusRomNo9L-Regu]{\def\pst@PSfontM{/#1 }}
+\define@key[psset]{pst-geometrictools}{fontsizeM}[6]{\def\pst@fontsizeM{#1 }}
+\define@key[psset]{pst-geometrictools}{country}[Germany]{\def\pst@country{#1}}
+\psset[pst-geometrictools]{ProScale=1,OwnerTxt={Euklid},MadeTxt={made in NES},
+ country=Germany,PSfontO=StandardSymL,PSfontM=NimbusRomNo9L-Regu,fontsizeO=10,fontsizeM=6,
+ ProFillCol=gray!60,ProLineCol=cyan,Ghost=false}
+
+
+\def\psProtractor{\def\pst@par{}\pst@object{psProtractor}}
+\def\psProtractor@i#1(#2){\@ifnextchar({\psProtractor@ii{#1}(#2)}{\psProtractor@ii{#1}(#2)(#2)}}%
+
+\def\psProtractor@ii#1(#2)(#3){%------------------------------- #1 Winkel, #2 Ursprung P, zweiter Punkt Q für Winkel
+ \begin@SpecialObj
+ \pst@killglue
+% \begingroup
+ \pnode(#2){@PGD}%
+ \pnode(#3){@QGD}%
+ \use@par
+ \pst@getcoor{@QGD}\pst@tempB % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempB
+ \pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
+ \addto@pscode{%
+ /sysfill {systemdict /fill get exec} def
+ /Country (\pst@country) def
+ /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
+ \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
+ \pst@tempB \tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
+ @y1 @y2 sub @x1 @x2 sub Atan /@delta ED %------------ Winkelberechnung
+ \pst@tempA \pst@coor T % ------------------------------------ Tranformiere den Koordinatenursprung in P
+ @delta #1 add 180 add rotate % ------------------------------ Drehe das gesamte Geodreieck
+ \pst@ProScale dup scale % -------- Skaliere das ganze Geodreieck
+ %-------------------------------------------------------------------------------------------------------------
+ gsave
+ \ifPst@Ghost\else
+ %-------------- Äußere Begrenzung des Geodreiecks -----------------------------------------------
+ gsave
+ newpath
+ -8 cm 0 moveto
+ 16 cm 0 rlineto
+ -8 cm 8 cm rlineto
+ closepath
+% gsave
+ 0.7 setlinewidth
+ 0.1 setgray
+ stroke
+% grestore
+ grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- Gefüllter innerer Teil des Geodreiecks -----------------------------------------------
+ gsave
+ newpath
+ -7.5 cm 0.5 22.5 tan mul cm moveto
+ 15 cm 0 rlineto
+ -7.5 cm 7.5 cm rlineto
+ closepath
+% gsave
+ \pst@usecolor\ProFillCol
+% [ /ca .1 /SetTransparency pdfmark % set transparency
+ 0.1 .setopacityalpha sysfill
+% grestore
+ grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- Millimetereinteilung auf der Grundseite -------------------------------------------
+ /mmBlinie { newpath
+ -7 cm 0 cm moveto
+ 0 cm 0.17 cm rlineto
+% closepath
+ gsave
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 0.1 cm 0 cm translate
+ } def
+gsave
+140 {mmBlinie} repeat
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- 0,5- cm-Einteilung auf der Grundseite ----------------------------------------------
+ /cmBlinie { newpath
+ -7 cm 0 cm moveto
+ 0 cm 0.27 cm rlineto
+% closepath
+ gsave
+ 0.55 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 0.5 cm 0 cm translate
+ } def
+gsave
+ 29 {cmBlinie} repeat
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- mm-Einteilung von der Grundseite nach oben ------------------------------------
+/mmlinie { newpath
+ -2.3 cm 0.3 cm moveto
+ 0.2 cm 0 rlineto
+ 2.2 cm 0.3 cm moveto
+ 0.2 cm 0 rlineto
+% closepath
+ gsave
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 0 cm 0.1 cm translate
+ } def
+gsave
+33 {mmlinie} repeat
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- 0,5 cm-Einteilung von der Grundseite nach oben --------------------------------
+/cmlinie { newpath
+ -4.5 cm 0.5 cm moveto
+ 2 cm 0 rlineto
+ 0.75 cm 0 rmoveto
+ 1.5 cm 0 rlineto
+ 0.5 cm 0 rmoveto
+ 1.5 cm 0 rlineto
+ 0.75 cm 0 rmoveto
+ 2 cm 0 rlineto
+% closepath
+ gsave
+ 0.6 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 0 cm 0.5 cm translate
+ } def
+%------------------------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- Clippen entlang eines Kreises der 0,5 cm-Einteilung von der Grundseite nach oben ------------------------------------
+/kreisring { newpath
+ 0 0 translate
+ 0 0 4.2 cm 0 180 arc
+ closepath
+ } def
+ gsave
+ kreisring clip
+ 7 {cmlinie} repeat
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- farbiger und transparenter Halb-Ring -----------------------------------------------------------------------------
+ gsave
+ newpath
+ 0 0 translate
+ 0 0 5.1 cm 6 174 arc
+ 0 0 4.8 cm 174 6 arcn
+ closepath
+% gsave
+ \pst@usecolor\ProLineCol
+% [ /ca .4 /SetTransparency pdfmark % set transparency
+ 0.4 .setopacityalpha
+ sysfill
+% grestore
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 1-Grad-Winkeleinteilung an der linken Kathete -----------------------------------------------------------------
+ gsave
+ 91 1 179 { /Wk exch def % ---------------------------------------------------- Schleifenvariable festlegen, die von 91° bis 179° geht
+ {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def %---------- xWS1=8/(tan(alpha)-1) --> SP der Geraden linke Kathete mit Ursprungsgeraden im Winkel alpha
+ {7.8 Wk sin Wk cos div 1 sub div} /xWS2 exch def % ------- xWS2=7,8/(tan(alpha)-1) --> SP einer Parallelen zur Geraden linke Kathete mit Ursprungsgeraden im Winkel alpha
+ newpath
+ xWS1 cm xWS1 8 add cm moveto % --------------------------- zu xWS1 gehöriger y-Wert ist xWS1 + 8
+ xWS2 cm xWS2 7.8 add cm % ----------------------------------- zu xWS2 gehöriger y-Wert ist xWS1 + 7,8
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 5-Grad-Winkeleinteilung an der linken Kathete -----------------------------------------------------------------
+ gsave
+ 95 5 175 { /Wk exch def
+ {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def
+ {7.6 Wk sin Wk cos div 1 sub div} /xWS2 exch def
+ newpath
+ xWS1 cm xWS1 8 add cm moveto
+ xWS2 cm xWS2 7.6 add cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 10-Grad-Winkeleinteilung an der linken Kathete -----------------------------------------------------------------
+ gsave
+ 100 10 170 { /Wk exch def
+ {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def
+ {5.1 Wk cos mul Wk cos div 1 sub div} /xWS2 exch def
+ newpath
+ xWS1 cm xWS1 8 add cm moveto
+ 5.1 Wk cos mul cm 5.1 Wk sin mul cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 1-Grad-Winkeleinteilung an der rechten Kathete ---------------------------------------------------------------
+ gsave
+ 1 1 89 { /Wk exch def
+ {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
+ {7.8 Wk sin Wk cos div 1 add div} /xWS2 exch def
+ newpath
+ xWS1 cm xWS1 neg 8 add cm moveto
+ xWS2 cm xWS2 neg 7.8 add cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 5-Grad-Winkeleinteilung an der rechten Kathete ---------------------------------------------------------------
+ gsave
+ 5 5 85 { /Wk exch def
+ {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
+ {7.6 Wk sin Wk cos div 1 add div} /xWS2 exch def
+ newpath
+ xWS1 cm xWS1 neg 8 add cm moveto
+ xWS2 cm xWS2 neg 7.6 add cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 10-Grad-Winkeleinteilung an der rechten Kathete --------------------------------------------------------------
+ gsave
+ 10 10 80 { /Wk exch def
+ {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
+ {5.1 Wk cos mul Wk cos div 1 add div} /xWS2 exch def
+ newpath
+ xWS1 cm xWS1 neg 8 add cm moveto
+ 5.1 Wk cos mul cm 5.1 Wk sin mul cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 1-Grad-Winkeleinteilung auf Halbkreis ------------ ---------------------------------------------------------------
+ gsave
+ 5 1 175 { /Wk exch def
+ newpath
+ 4.3 Wk cos mul cm 4.3 Wk sin mul cm moveto
+ 4.45 Wk cos mul cm 4.45 Wk sin mul cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- 5-Grad-Winkeleinteilung auf Halbkreis ------------ ---------------------------------------------------------------
+ gsave
+ 5 5 175 { /Wk exch def
+ newpath
+ 4.3 Wk cos mul cm 4.3 Wk sin mul cm moveto
+ 4.5 Wk cos mul cm 4.5 Wk sin mul cm
+ lineto
+% closepath
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ } for
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%-------------------------- Linke Diagonallinie-dashed -------------------------------------------------------------------------------
+ gsave
+ newpath /Wk 135 def
+ {8 Wk sin Wk cos div 1 sub div} /xWS1 exch def
+ 0 0 moveto
+ 4.3 Wk cos mul cm 4.3 Wk sin mul cm lineto
+% closepath
+ gsave
+ [2 sqrt 2 div 0.24 sub cm 0.24 cm] -0.12 cm setdash
+ 0.5 setlinewidth
+ 0 setgray stroke
+ grestore
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%-------------------------- Rechte Diagonallinie-dashed -----------------------------------------------------------------------------
+ gsave
+ newpath /Wk 45 def
+ {8 Wk sin Wk cos div 1 add div} /xWS1 exch def
+ 0 0 moveto
+ 4.3 Wk cos mul cm 4.3 Wk sin mul cm lineto
+% closepath
+ gsave
+ [2 sqrt 2 div 0.24 sub cm 0.24 cm] -0.12 cm setdash
+ 0.5 setlinewidth
+ 0 setgray stroke
+ grestore
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------
+%---------------------------------------- Mittel-Linie -------------------------------------------------------------------------------------
+ gsave
+ newpath
+ 0 0.5 cm moveto
+ 0 3.5 cm lineto
+ 0 5.1 cm moveto
+ 0 6.0 cm lineto
+ 0 6.4 cm moveto
+ 0 8.0 cm lineto
+% closepath
+ gsave
+ 0.5 setlinewidth
+ 0 setgray stroke
+ grestore
+ grestore
+%--------------------------------------------------------------------------------------------------------------------------------------------------
+%------------------------- Definition für horizontal-zentriertes - Setzen der cm- Zahlen (180° gedreht) ------------------------
+ /cmshow {% (string) x y
+ gsave
+ moveto 180 rotate % s
+ /NimbusRomNo9L-Regu findfont 7 scalefont setfont
+ dup % s s
+ stringwidth pop 2 div neg 0 % s -dx/2
+ rmoveto 0.2 setgray show
+ grestore
+ } bind def
+%------------------------- Setzen der Zahlen für die cm-Einteilungen -----------------------------------------------------------------
+ 0 1 7 { /MZ exch def MZ 2 string cvs MZ cm 0.47 cm cmshow } for %---------------- Zahlen 0 bis 7 (nach rechts)
+ 1 1 7 { /MZ exch def MZ 2 string cvs MZ neg cm 0.47 cm cmshow } for %----------- Zahlen 1 bis 7 (nach links)
+ 1 1 3 { /MZ exch def MZ 2 string cvs 2 cm MZ 0.1 add cm cmshow } for %---------- Zahlen 1 bis 3 (nach oben, rechte Seite)
+ 1 1 3 { /MZ exch def MZ 2 string cvs -2 cm MZ 0.1 add cm cmshow } for %--------- Zahlen 1 bis 3 (nach oben, linke Seite)
+%--------------------------------------------------------------------------------------------------------------------------------------------------
+%------------------------- Definition für horizontal-zentriertes - Setzen der Winkel- Zahlen (mitgedreht) ----------------------
+ /cmRotshow {% ---------------------------------- (string), Winkel, x y
+ gsave
+ moveto 90 add rotate % s
+ /NimbusRomNo9L-Regu findfont 7 scalefont setfont
+ dup % s s
+ stringwidth pop 2 div neg 0 % s -dx/2
+ rmoveto 0.2 setgray show
+ grestore
+ } bind def
+ gsave
+%------------------------- Setzen der Zahlen für die Winkel-Einteilungen -------------------------------------------------------------------------------------------------
+ 10 10 170 { /MZ exch def MZ 3 string cvs MZ 5.03 cm MZ cos mul 5.03 cm MZ sin mul cmRotshow } for % ------------------ äußerer Kreisbogen
+ 10 10 170 { /MZ exch def 180 MZ sub 3 string cvs MZ 4.75 cm MZ cos mul 4.75 cm MZ sin mul cmRotshow } for % ------- innerer Kreisbogen
+ grestore
+%---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /TSshow {% (string) x y
+ gsave
+ moveto 180 rotate % s
+ \pst@PSfontO\space findfont \pst@fontsizeO scalefont setfont
+ dup % s s
+ stringwidth pop 2 div neg 0 % s -dx/2
+ rmoveto 0.4 setgray show
+ grestore
+ } bind def
+ gsave
+ (\pst@OwnerTxt) 0 cm 4 cm TSshow
+ grestore
+%--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ /MadeShow {% (string) x y
+ gsave
+ moveto 180 rotate % s
+ \pst@PSfontM\space findfont \pst@fontsizeM scalefont setfont
+ dup % s s
+ stringwidth pop 2 div neg 0 % s -dx/2
+ rmoveto 0.7 setgray show
+ grestore
+ } bind def
+ gsave
+ (\pst@MadeTxt) 0 cm 6.25 cm MadeShow
+ grestore
+%---------------------------------------- Fahne -------------------------------------------------------------------------------------
+ gsave
+ /Fahne {
+ newpath
+ 0 0 moveto
+ 0 1 rlineto
+ 1 0 rlineto
+ 0 -1 rlineto
+ closepath
+ setrgbcolor
+% [ /ca .5 /SetTransparency pdfmark % set transparency
+ 0.5 .setopacityalpha sysfill
+ } def
+Country (France) eq {
+ 0.73 cm 6.1 cm translate
+ 3 6 scale
+ 1 0 0 Fahne
+ 1 0 translate
+ 1 1 1 Fahne
+ 1 0 translate
+ 0 0 1 Fahne
+ } if
+Country (Germany) eq {
+ 0.775 cm 6.22 cm translate
+ 7.5 1.5 scale
+ 1 0.588 0 Fahne
+ 0 -1 translate
+ 0.75 0.07 0.11 Fahne
+ 0 -1 translate
+ 0 0 0 Fahne
+ } if
+ grestore
+%--------------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- Ende nur grestore von gsave ganz am Anfang ------------------
+\fi
+grestore
+}%
+\pnode(!
+ /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
+ \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
+ \pst@tempB \tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
+ @y1 @y2 sub @x1 @x2 sub Atan /@delta ED %------------ Winkelberechnung
+ @x1 cm @y1 cm T % ------------------------------------ Tranformiere den Koordinatenursprung in P
+ @delta #1 add 180 add rotate % ------------------------------ Drehe den oberen Punkt des Geodreiecks
+ \pst@ProScale\space \pst@ProScale\space scale % -------- Skalieren!
+ 0 8){GeodrC}%
+\pnode(!
+ @x1 cm @y1 cm T % ------------------------------------ Tranformiere den Koordinatenursprung in P
+ @delta #1 add 180 add rotate % ------------------------------ Drehe die linke untere Ecke des Geodreiecks
+ \pst@ProScale\space \pst@ProScale\space scale % -------- Skalieren!
+ -8 0){GeodrA}%
+\pnode(!
+ @x1 cm @y1 cm T % ------------------------------------ Tranformiere den Koordinatenursprung in P
+ @delta #1 add 180 add rotate % ------------------------------ Drehe die rechte untere Ecke des Geodreiecks
+ \pst@ProScale\space \pst@ProScale\space scale % -------- Skalieren!
+ 8 0){GeodrB}%
+%\endgroup%
+ \end@SpecialObj
+ \ignorespaces
+}%
+
+\definecolor{HolzCol}{rgb}{1,0.937,0.835}%
+\define@key[psset]{pst-geometrictools}{PenScale}[1]{\def\pst@PenScale{#1 }}%
+\define@key[psset]{pst-geometrictools}{PenLength}[5]{\def\pst@PenLength{#1 }}%
+\define@key[psset]{pst-geometrictools}{pencilColA}[red]{\pst@getcolor{#1}\pencilColA}
+\define@key[psset]{pst-geometrictools}{pencilColB}[HolzCol]{\pst@getcolor{#1}\pencilColB}
+\psset[pst-geometrictools]{PenLength=5,pencilColA=red,pencilColB=HolzCol,PenScale=1}
+
+\def\psPencil{\def\pst@par{}\pst@object{psPencil}}
+\def\psPencil@i#1(#2){%------------------------------- #1 Winkel, #2 Ursprung P
+\begin@SpecialObj
+\pst@killglue
+\begingroup
+\pnode(#2){@PGD}%
+\use@par
+\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
+\addto@pscode{
+/sysfill {systemdict /fill get exec} def
+%/Country (\pst@country) def
+ /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
+ /Plength \pst@PenLength def
+% \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
+ \pst@tempA \pst@coor T % ------------------------------------ Tranformiere den Koordinatenursprung in P
+ #1 rotate % ------------------------------ Drehe das gesamte Geodreieck
+ \pst@PenScale dup scale % -------- Skaliere das ganze Geodreieck
+%-------------------------------------------------------------------------------------------------------------
+gsave
+%-------------------------------------------------------------------------------------------------------------
+%-------------- Unterer Holzteil des Stifts -------------------------------------------------------------
+gsave
+ newpath
+ 0 cm 0 moveto
+ -0.3 cm 1 cm rlineto
+ 0 cm 0.2 cm rlineto
+ 0.6 cm 0 cm rlineto
+ 0 cm -0.2 cm rlineto
+ closepath
+ gsave
+ \pst@usecolor\pencilColB
+ fill
+ grestore
+ gsave
+ 0.4 setlinewidth
+ 0.5 setgray
+ 1 setlinejoin
+ stroke
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- langer farbiger Teil des Stifts ----------------------------------------------------------
+gsave
+ newpath
+ -0.3 cm 1 cm moveto
+ 0 cm Plength cm rlineto
+ 0.6 cm 0 cm rlineto
+ 0 cm Plength neg cm rlineto
+ 0.3 cm 1.13 cm 0.13 cm 270 180 arcn
+ 0 cm 1.13 cm 0.17 cm 0 180 arcn
+ -0.3 cm 1.13 cm 0.13 cm 0 270 arcn
+ closepath
+ gsave
+ \pst@usecolor\pencilColA
+ fill
+ grestore
+ gsave
+ 0.5 setlinewidth
+ 0.1 setgray
+ stroke
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%--------------------------- Spitze in Farbe --------------------------------------------------------------
+gsave
+ newpath
+ 0 cm 0 moveto
+ -0.1 cm 1 3 div cm rlineto
+ 0.2 cm 0 cm rlineto
+ closepath
+ gsave
+ \pst@usecolor\pencilColA
+ fill
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%--------------------------- Striche im Stift --------------------------------------------------------------
+gsave
+ newpath
+ -0.17 cm 1.13 cm moveto
+ 0 cm Plength 0.13 sub cm rlineto
+ 0.17 cm 1.13 cm moveto
+ 0 cm Plength 0.13 sub cm rlineto
+ closepath
+ gsave
+ 0.5 setlinewidth
+ 0.1 setgray
+ stroke
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%--------------------------- Elliptisches Stift-Ende in Holz --------------------------------------------
+gsave
+ newpath
+ 0 cm Plength 1 add cm T
+ 1 0.2 scale
+ 0 cm 0 cm 0.3 cm 0 360 arc
+ closepath
+ gsave
+ \pst@usecolor\pencilColB
+ fill
+ grestore
+ gsave
+ 0.5 setlinewidth
+ 0.3 setgray
+ stroke
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%--------------------------- Elliptisches Stift-Ende in Farbe -------------------------------------------
+gsave
+ newpath
+ 0 cm Plength 1 add cm T
+ 1 0.2 scale
+ 0 cm 0 cm 0.1 cm 0 360 arc
+ closepath
+ gsave
+ \pst@usecolor\pencilColA
+ fill
+ grestore
+ gsave
+ 0.3 setlinewidth
+ 0.3 setgray
+ stroke
+ grestore
+grestore
+%--------------------------------------------------------------------------------------------------------
+%--------------------------------------------------------------------------------------------------------
+grestore
+}%
+\endgroup
+\end@SpecialObj\ignorespaces
+}%
+
+
+\define@key[psset]{pst-geometrictools}{RulerFillCol}[cyan!60]{\pst@getcolor{#1}\RulerFillCol}
+\define@key[psset]{pst-geometrictools}{RulerScale}[1]{\def\pst@RulerScale{#1 }}%
+\psset[pst-geometrictools]{RulerFillCol=gray,RulerScale=1}
+
+\def\psRuler{\def\pst@par{}\pst@object{psRuler}}
+\def\psRuler@i#1(#2){\@ifnextchar(%
+{\psRuler@ii{#1}(#2)}%
+{\psRuler@ii{#1}(#2)(#2)}}%
+\def\psRuler@ii#1(#2)(#3){%------------------------------- #1 Winkel, #2 Ursprung P, zweiter Punkt Q für Winkel
+\begin@SpecialObj
+\pst@killglue
+\begingroup%
+\pnode(#2){@PGD}%
+\pnode(#3){@QGD}%
+\use@par%
+\pst@getcoor{@QGD}\pst@tempB % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempB
+\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
+\addto@pscode{
+/sysfill {systemdict /fill get exec} def
+ /cm {28.45274 mul} def % --------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
+ \pst@tempA \tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
+ \pst@tempB \tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
+ @y1 @y2 sub @x1 @x2 sub Atan /@delta ED %------------ Winkelberechnung
+ \pst@tempA \pst@coor T % ------------------------------------ Tranformiere den Koordinatenursprung in P
+ @delta #1 add 180 add rotate % ------------------------------ Drehe das gesamte Geodreieck
+ \pst@RulerScale dup scale % ----------------------------------- Skaliere das ganze Geodreieck
+%-------------------------------------------------------------------------------------------------------------
+gsave
+%-------------------------------------------------------------------------------------------------------------
+%-------------- Füllung der beiden inneren Bereiche und äußere Begrenzung des Lineals -----------------------------------------------
+gsave
+ newpath
+ -0.2 cm 0 moveto
+ 30.4 cm 0 rlineto
+ 0 cm -0.9 cm rlineto
+ -30.4 cm 0 cm rlineto
+ closepath
+ gsave
+ \pst@usecolor\RulerFillCol
+% [ /ca .25 /SetTransparency pdfmark % set transparency
+ 0.25 .setopacityalpha sysfill
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+gsave
+ newpath
+ -0.2 cm 0 moveto
+ 30.2 cm 0 lineto
+ 0 cm -3 cm rlineto
+ -30.4 cm 0 cm rlineto
+ closepath
+ 3.75 cm -1.5 cm moveto
+ 3.5 cm -1.5 cm 0.25 cm 0 360 arc
+ closepath
+ gsave
+ \pst@usecolor\RulerFillCol
+% [ /ca .15 /SetTransparency pdfmark % set transparency
+ 0.15 .setopacityalpha sysfill
+ grestore
+ gsave
+% 2 setlinejoin
+ 0.7 setlinewidth
+ 0.1 setgray
+ stroke
+ grestore
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- Millimetereinteilung auf der Grundseite -------------------------------------------
+ /mmBlinie { newpath
+ 0 cm 0 cm moveto
+ 0 cm -0.25 cm rlineto
+ gsave
+ 0.5 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 0.1 cm 0 cm translate
+ } def
+gsave
+300 {mmBlinie} repeat
+grestore
+%-------------------------------------------------------------------------------------------------------------
+%-------------- 0,5- cm-Einteilung auf der Grundseite ----------------------------------------------
+ /cmBlinie { newpath
+ 0.5 cm 0 cm moveto
+ 0 cm -0.375 cm rlineto
+% closepath
+ gsave
+ 0.55 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 1 cm 0 cm translate
+ } def
+gsave
+ 30 {cmBlinie} repeat
+grestore
+%-------------- 1- cm-Einteilung auf der Grundseite ----------------------------------------------
+ /cmBlinie { newpath
+ 0 cm 0 cm moveto
+ 0 cm -0.5 cm rlineto
+% closepath
+ gsave
+ 0.6 setlinewidth
+ 0 setgray
+ stroke
+ grestore
+ 1 cm 0 cm translate
+ } def
+gsave
+ 31 {cmBlinie} repeat
+grestore
+%--------------------------------------------------------------------------------------------------------------------------------------------------
+%------------------------- Definition für horizontal-zentriertes - Setzen der cm- Zahlen (180° gedreht) ------------------------
+ /cmshow {% (string) x y
+ gsave
+ moveto % s
+ /NimbusRomNo9L-Regu findfont 8 scalefont setfont
+ dup % s s
+ stringwidth pop 2 div neg 0 % s -dx/2
+ rmoveto 0.2 setgray show
+ grestore
+ } bind def
+%------------------------- Setzen der Zahlen für die cm-Einteilungen -----------------------------------------------------------------
+ 0 1 30 { /MZ exch def MZ 2 string cvs MZ cm -0.78 cm cmshow } for %---------------- Zahlen 0 bis 30 (nach rechts)
+%-------------------------------------------------------------------------------------------------------------
+%--------------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- Ende nur grestore von gsave ganz am Anfang ------------------
+grestore
+}%
+\endgroup%
+\end@SpecialObj\ignorespaces
+}%
+
+\definecolor{PoCRed}{rgb}{0.7,0.134,0.134}
+\define@boolkey[psset]{pst-geometrictools}[Pst@]{MCAngle}[true]{}
+\define@key[psset]{pst-geometrictools}{PoCLength}[5]{\def\pst@PoCLength{#1 }}
+\define@key[psset]{pst-geometrictools}{PoCAngle}[0]{\def\pst@PoCAngle{#1 }}
+\define@key[psset]{pst-geometrictools}{PoCFillCol}[PoCRed]{\pst@getcolor{#1}\PoCFillCol}
+\define@key[psset]{pst-geometrictools}{PoCMineCol}[black!80]{\pst@getcolor{#1}\PoCMineCol}
+\define@key[psset]{pst-geometrictools}{PoCScale}[1]{\def\pst@PoCScale{#1 }}%
+\define@key[psset]{pst-geometrictools}{RadVS}[RVS]{\def\pst@RadVS{#1}}%
+\define@key[psset]{pst-geometrictools}{AngleVS}[AVS]{\def\pst@AngleVS{#1}}%
+\define@key[psset]{pst-geometrictools}{RadMul}[1]{\def\pst@RadMul{#1 }}%
+\psset[pst-geometrictools]{PoCScale=1,PoCFillCol=PoCRed,PoCAngle=0,PoCMineCol=black!80,PoCLength=5,MCAngle=true,RadVS=RVS,AngleVS=AVS,RadMul=1}
+
+\def\psCompass{\def\pst@par{}\pst@object{psCompass}}% Pair of Compasses
+\def\psCompass@i#1(#2){\@ifnextchar(%
+{\psCompass@ii{0}(#2)}%
+{\psCompass@ii{#1}(#2)(#2)}}%
+\def\psCompass@ii#1(#2)(#3){%------------------------------- #1 Winkel, #2 Ursprung P, zweiter Punkt Q für Winkel
+\begin@SpecialObj
+\pst@killglue
+\begingroup%
+\pnode(#2){@PGD}%
+\pnode(#3){@QGD}%
+\use@par%
+\pst@getcoor{@QGD}\pst@tempB % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempB
+\pst@getcoor{@PGD}\pst@tempA % -------------------------- Hohle die Koordinaten und speichere sie in \pst@tempA
+\addto@pscode{%
+ \pst@RadMul /faktor ED
+ \pst@PoCScale /skal ED
+ #1 skal div 2 div /Radius ED
+ skal dup scale % -------- Skaliere das ganze Geodreieck
+ /sysfill {systemdict /fill get exec} def
+ /SLg \pst@PoCLength def
+ /cm {28.45274 mul} def % ---------------------------------------- Definiere cm als Längeneinheit mit der multipliziert wird
+ \pst@tempA\tx@UserCoor /@y1 ED /@x1 ED % ---------- Definiere die Koordinaten des Ursprungs (zur Winkelberechnung benötigt)
+ \pst@tempB\tx@UserCoor /@y2 ED /@x2 ED % ---------- Definiere die Koordinaten des zweiten Punktes (zur Winkelberechnung benötigt)
+ \pst@tempA\pst@coor /@y3 ED /@x3 ED
+ @y1 @y2 sub dup mul @x1 @x2 sub dup mul add faktor dup mul mul /quadlg ED
+ quadlg 0 eq { 180 } { @y1 @y2 sub @x1 @x2 sub atan } ifelse /@delta ED %------------ Winkelberechnung
+ quadlg sqrt 2 div /RadiusPktB ED %------------ Radiusberechnung mit zweitem Punkt
+ SLg RadiusPktB Radius add gt { RadiusPktB Radius add } { SLg } ifelse /RadPoC ED
+ /hoehe SLg dup mul RadPoC dup mul sub sqrt def
+ /phiS RadPoC hoehe atan def
+ @x3 @y3 T % ------------------------------------------------------------------------------- Transformiere den Koordinatenursprung in P
+ \pst@PoCAngle\space \ifPst@MCAngle\space @delta add 180 add \fi rotate % ------------------------------ Drehe das gesamte Geodreieck
+%-------------------------------------------------------------------------------------------------------------
+gsave
+%-------------------------------------------------------------------------------------------------------------
+%-------------- Linke Zirkelspitze----------------------------------------------- 0 cm 0 cm 0.15 cm 0 360 arc
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm 0 cm moveto
+ -0.1 cm 0.33 cm lineto
+ 0.07 cm 0 cm rlineto
+ closepath
+ gsave
+ 0.5 setgray
+ fill
+ grestore
+grestore
+%---------------------------------------- rechte Zirkel-Mine --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm T
+ phiS 2 mul rotate
+ 0 cm SLg neg cm moveto
+ 0.06 cm 0.1 cm rlineto
+ 0.013 cm 0.2 cm rlineto
+ -0.06 cm 0 cm rlineto
+ closepath
+ gsave
+ \pst@usecolor\PoCMineCol
+ fill
+ grestore
+grestore
+%---------------------------------------- Spindel --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ -2 cm -1 phiS cos mul cm rmoveto
+ 4 cm 0 cm rlineto
+ gsave
+ 0.5 setgray
+ 1.6 setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ -2 cm -1 phiS cos mul cm rmoveto
+ 0.2 -0.75 rmoveto
+ 189 { 0.5 1.5 rlineto
+ 0.1 -1.5 rmoveto } repeat
+ gsave
+ 0.2 setgray
+ 0.2 setlinewidth
+ stroke
+ grestore
+grestore
+%---------------------------------------- Drehrad an der Spindel --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ 0 cm -1.3 phiS cos mul cm rmoveto
+ 0 cm 0.6 cm rlineto
+ gsave
+ 0.5 setgray
+ 0.08 cm setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ -0.04 cm -1.28 phiS cos mul cm rmoveto
+ 20 { 0.08 cm 0 cm rlineto
+ -0.08 cm 0.03 cm rmoveto } repeat
+ gsave
+ 0.3 setgray
+ 0.2 setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+%---------------------------------------- Halterung zum Anfassen --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ 0 cm 0.75 0.54 phiS sin mul add cm moveto
+ 0 cm 0.2 cm rlineto
+ gsave
+ 0.5 setgray
+ 3 setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ 0 cm 0.95 0.54 phiS sin mul add cm moveto
+ 0 cm 0.05 cm rlineto
+ gsave
+ \pst@usecolor\PoCFillCol
+ 5 setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ 0 cm 1.0 0.54 phiS sin mul add cm moveto
+ 0 cm 0.5 cm rlineto
+ gsave
+ 0.5 setgray
+ 5 setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ -0.08 cm 1.0 0.6 phiS sin mul add cm moveto
+ 0 cm 0.48 cm rlineto
+ 6 { 0.025 cm -0.48 cm rmoveto
+ 0 cm 0.48 cm rlineto } repeat
+ gsave
+ 0.65 setgray
+ 0.15 setlinewidth
+ stroke
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ -0.075 cm 1.0 0.6 phiS sin mul add cm moveto
+ 0 cm 0.48 cm rlineto
+ 6 { 0.025 cm -0.48 cm rmoveto
+ 0 cm 0.48 cm rlineto } repeat
+ gsave
+ 0.25 setgray
+ 0.2 setlinewidth
+ stroke
+ grestore
+grestore
+%---------------------------------------- Kreis um oberen Teil --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm T
+ phiS rotate
+ 0 cm 0.1 0.54 phiS sin mul add cm moveto
+ 0.65 -50 PtoC exch cm exch cm rmoveto
+ 0 cm 0.1 0.54 phiS sin mul add cm 0.65 cm -50 230 arc
+ gsave
+ 0.1 setgray
+ 1.3 setlinewidth
+ stroke
+ grestore
+grestore
+%---------------------------------------- Kreis zwischen den Schenkeln --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm moveto
+ 0 cm SLg cm 0.15 cm 0 360 arc
+ closepath
+ gsave
+ 0.1 setgray
+ fill
+ grestore
+grestore
+%---------------------------------------- Schenkel des Zirkels ----------------------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm 0.3 cm moveto
+ -0.3 cm SLg 0.1 add cm lineto
+ 0 cm SLg cm T
+ phiS 2 mul rotate
+ 0.3 cm 0.1 cm moveto
+ 0 cm SLg 0.3 sub neg cm lineto
+% closepath
+ gsave
+ 0.285 cm setlinewidth
+ 2 setlinejoin
+ \pst@usecolor\PoCFillCol
+ stroke
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ -0.17 cm SLg 0.6 mul cm moveto
+ -0.25 cm SLg 0.85 mul cm lineto
+ 0 cm SLg cm T
+ phiS 2 mul rotate
+ 0.17 cm SLg -0.4 mul cm moveto
+ 0.25 cm SLg -0.15 mul cm lineto
+% closepath
+ gsave
+ 0.17 cm setlinewidth
+ 2 setlinejoin
+ 0.4 setgray
+ stroke
+ grestore
+grestore
+%---------------------------------------- Kreis an der linken Spitze --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ -0.03 cm 0.8 cm moveto
+ -0.03 cm 0.8 cm 0.175 cm 0 360 arc
+ closepath
+ gsave
+ 0.25 setgray
+ fill
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ -0.03 cm 0.8 cm moveto
+ -0.03 cm 0.8 cm 0.025 cm 0 360 arc
+ closepath
+ gsave
+ 0.8 setgray
+ fill
+ grestore
+grestore
+%---------------------------------------- Kreis an der rechten Spitze --------------------------------------
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm T
+ phiS 2 mul rotate
+ 0.03 cm 0 cm T
+ 0 cm SLg 0.8 sub neg cm moveto
+ 0 cm SLg 0.8 sub cm neg 0.175 cm 0 360 arc
+ closepath
+ gsave
+ 0.25 setgray
+ fill
+ grestore
+grestore
+gsave
+ newpath
+ phiS neg rotate
+ 0 cm SLg cm T
+ phiS 2 mul rotate
+ 0.03 cm 0 cm T
+ 0 cm SLg 0.8 sub neg cm moveto
+ 0 cm SLg 0.8 sub cm neg 0.025 cm 0 360 arc
+ closepath
+ gsave
+ 0.8 setgray
+ fill
+ grestore
+grestore
+%--------------------------------------------------------------------------------------------------------------------------------------------------
+%--------------- Ende nur grestore von gsave ganz am Anfang ------------------
+grestore
+}%
+\pnode(!
+ \pst@tempA \tx@UserCoor /@@y1 ED /@@x1 ED
+ \pst@tempB \tx@UserCoor /@@y2 ED /@@x2 ED
+ @@x1 @@x2 sub @@y1 @@y2 sub Pyth \pst@RadMul\space mul /\pst@RadVS\space exch def
+ @@y1 @@y2 sub dup mul @@x1 @@x2 sub dup mul add \pst@RadMul dup mul mul /quadlg ED
+ quadlg 0 eq { 180 } { @@y1 @@y2 sub @@x1 @@x2 sub atan } ifelse /\pst@AngleVS\space exch def %------------ Winkelberechnung /\pst@AngleVS\space exch def
+ 0 0){MoneyforNothing}%
+\endgroup%
+\end@SpecialObj\ignorespaces%
+}%
+
+%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ruler}[true]{}
+%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ppoint}[false]{}
+%\define@boolkey[psset]{pst-geometrictools}[Pst@]{LineOffset}[false]{}
+%\define@key[psset]{pst-geometrictools}{AddAngle}[0]{\def\pst@AddAngle{#1 }}%
+%\psset[pst-geometrictools]{Ruler=true,Ppoint=false,AddAngle=0,LineOffset=false}
+
+%% Distance between two points => #3
+\def\psDistAB(#1)(#2)#3{%
+ \pst@getcoor{#1}\pst@tempA
+ \pst@getcoor{#2}\pst@tempB
+\pnode(!
+ \pst@tempA \tx@UserCoor
+ \pst@tempB \tx@UserCoor
+ 3 -1 roll sub dup mul 3 1 roll sub dup mul add sqrt
+ /#3 ED
+ 0 0
+ ){XX}
+}
+%% calcule l'angle entre Ox et AB et le place en #3
+\def\psAngleAB(#1)(#2)#3{%
+ \pst@getcoor{#1}\pst@tempA
+ \pst@getcoor{#2}\pst@tempB
+\pnode(!
+ \pst@tempA \tx@UserCoor
+ \pst@tempB \tx@UserCoor
+ 3 -1 roll sub 3 1 roll exch sub Atan
+ /#3 ED
+ 0 0
+ ){YY}
+}%
+%% angle defined by three points
+\def\psAngleAOB(#1)(#2)(#3)#4{%
+ \pst@getcoor{#1}\pst@tempA
+ \pst@getcoor{#2}\pst@tempB
+ \pst@getcoor{#2}\pst@tempC
+\pnode(!
+ \pst@tempA \tx@UserCoor
+ \pst@tempB \tx@UserCoor
+ \pst@tempC \tx@UserCoor
+ 4 copy exch 4 -1 roll mul
+ 3 -2 roll mul add
+ 4 -2 roll mul 4 -2 roll mul sub exch Atan
+ /#4 ED
+ 0 0
+ ){ZZ}
+}
+
+% la nouvelle version de \psParallels
+\define@key[psset]{pst-geometrictools}{DistCoeff}[1]{\def\pst@DistCoeff{#1 }}%
+\psset[pst-geometrictools]{DistCoeff=1}
+%
+\def\psParallels{\def\pst@par{}\pst@object{psParallels}}
+\def\psParallels@i(#1)(#2)(#3){%
+% \begin@SpecialObj
+ \pst@killglue
+ \begingroup
+ \use@par
+ \pnode(#1){pointA}%
+ \pnode(#2){pointB}%
+ \pnode(#3){pointC}%
+ \pcline[nodesep=-3](pointA)(pointB)
+ \psdots(pointA)(pointB)(pointC)
+% \uput[l](pointA){A}\uput[l](pointB){B}\uput[r](pointC){C}
+%
+ \psProtractor[Ghost]{0}(pointA)%
+ \psAngleAB(pointA)(pointB){alpha1}
+ \psAngleAB(pointA)(GeodrA){alpha2}
+% \psdot(GeodrA)\uput[-90](GeodrA){A'}% right edge of triangle
+ \psProtractor[Ghost]{alpha1 alpha2 sub }(pointA)%
+% \psdot(GeodrA)\uput[-90](GeodrA){A''}% right edge of triangle
+% \psdot(GeodrB)\uput[-90](GeodrB){B''}% left edge of triangle
+% \psdot(GeodrC)\uput[-90](GeodrC){C''}% bottom edge of triangle
+ \psRuler{0}(GeodrB)(GeodrC)
+%
+ \pstProjection[PointName={},PointSymbol=none]{pointA}{pointB}{pointC}[pointI]%
+ \pstRotation[RotAngle=45,PointSymbol=none,PointName={}]{pointC}{pointI}[pointJ]%
+ \pstInterLL[PointSymbol=none,PointName={}]{pointA}{pointB}{pointC}{pointJ}{pointK}%
+ \pstTranslation[PointSymbol=none,PointName={},DistCoef=\pst@DistCoeff]{pointK}{pointC}{pointA}[pointA*]
+ \psProtractor{alpha1 alpha2 sub}(pointA*)%
+ \endgroup
+ \ignorespaces%
+}%
+
+%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ruler}[true]{}
+%\define@boolkey[psset]{pst-geometrictools}[Pst@]{Ppoint}[false]{}
+%\define@boolkey[psset]{pst-geometrictools}[Pst@]{LineOffset}[false]{}
+%\define@key[psset]{pst-geometrictools}{AddAngle}[1]{\def\pst@AddAngle{#1 }}%
+%\psset[pst-geometrictools]{Ruler=true,Ppoint=false,AddAngle=0,LineOffset=false}
+%\def\psParallels{\def\pst@par{}\pst@object{psParallels}}
+%\def\psParallels@i(#1)(#2)(#3){%
+%\psset{saveNodeCoors,NodeCoorPrefix=n}%
+%\@ifundefined{rCounter}{\def\rCounter{1}}{}%
+%\begin@SpecialObj %
+%\pnode(#1){pointA}%
+%\pnode(#2){pointB}%
+%\pnode(#3){pointC}%
+%\pstProjection[PointName={},PointSymbol=none]{pointA}{pointB}{pointC}[pointI]%
+%\midAB(pointA)(pointB){pointM}%
+%\pstRotation[RotAngle=45,PointSymbol=none,PointName={}]{pointC}{pointI}[pointJ]%
+%\pstInterLL[PointSymbol=none,PointName={}]{pointA}{pointB}{pointC}{pointJ}{pointK}%
+%\AtoB(pointI)(pointC){IC}%
+%\AtoB(pointK)(pointC){KC}%
+%\AplusB(pointM)(KC){MT}%
+%\AplusB(pointB)(KC){BT}%
+%\psProtractor[Ghost]{0}(pointM)(pointB)%
+%\pnode(GeodrB){ProB}%
+%\pnode(GeodrC){ProC}%
+%\psLDNode(ProB)(ProC){-1cm}{pointE}%
+%\ifPst@Ruler\psRuler{0}(pointE)(GeodrC)\fi%
+%\AplusB(ProB)(KC){ProB*}%
+%\pst@Verb{ nKCx nKCy Pyth /laenge exch def %
+%nKCx laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delX exch def %
+%nKCy laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delY exch def
+%}%
+%\pnode(!nProB*x delX add nProB*y delY add ){GProB*}%
+%\pnode(!/AddA \pst@AddAngle def nProB*x AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse nProB*y AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){GProBC*}%
+%\pnode(!nMTx delX add nMTy delY add){GMT*}%
+%\pnode(!/AddA \pst@AddAngle def npointCx AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse npointCy AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){pointC*}%
+%\psLNode(pointM)(GMT*){\rCounter}{MPro}%
+%\psLNode(ProB)(GProB*){\rCounter}{BPro}%
+%\ifPst@Ppoint
+%\ifPst@LineOffset
+%\pst@Verb{ nICx nICy Pyth /laenge exch def %
+%nICx laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delX exch def %
+%nICy laenge div \pst@number\pslinewidth\space 2 div 0.35 \pst@ProScale mul add mul 28.45274 div 2 sqrt mul /delY exch def %
+%}%
+%\pnode(!/AddA \pst@AddAngle def nProB*x AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse nProB*y AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){GProBC*}%
+%\pnode(!/AddA \pst@AddAngle def npointCx AddA 0 eq { delX add } { AddA 180 eq { delX sub } { 0 add } ifelse } ifelse npointCy AddA 0 eq { delY add } { AddA 180 eq { delY sub } { 0 add } ifelse } ifelse ){pointC*}%
+%\psProtractor{\pst@AddAngle}(pointC*)(GProBC*)\else%
+%\psProtractor{\pst@AddAngle}(pointC)(ProB*)\fi%
+%\else
+%\psProtractor{\pst@AddAngle}(MPro)(BPro)\fi % Um die Liniendicke 0.8pt nach rechts versetzt
+%\psLNode(pointC)(ProB*){0.98}{ProB**}%
+%\psLNode(pointC)(ProB**){2}{C*}%
+%\end@SpecialObj\ignorespaces%
+%}%
+
+\catcode`\@=\PstAtCode\relax
\endinput \ No newline at end of file