%% $Id: pst-3dplot.pro 21 2020-08-04 12:53:07Z herbert $
%%
%% This is file `pst-3dplot.pro',
%%
%% IMPORTANT NOTICE:
%%
%% Package `pst-3dplot.tex'
%%
%% Herbert Voss <voss _at_ PSTricks.de>
%%
%% This program can be redistributed and/or modified under the terms
%% of the LaTeX Project Public License Distributed from CTAN archives
%% in directory macros/latex/base/lppl.txt.
%%
%% DESCRIPTION:
%%   `pst-3dplot' is a PSTricks package to draw 3d curves and graphical objects
%%
%%
%% version 0.33 / 2017-04-05  Herbert Voss <hvoss _at_ tug.org>
%% with contributions of Darrell Lamm <darrell.lamm _at_ gtri.gatech.edu<
%%
%
/tx@3DPlotDict 200 dict def
tx@3DPlotDict begin
%
/printDot { gsave 2 copy 2 0 360 arc fill stroke grestore } def
%
/saveCoor {
 dzUnit mul /z ED
 dyUnit mul /y ED
 dxUnit mul /x ED
} def
%
/3Dto2D { % true or false on stack
 { RotatePoint } if
 1 { %  dummy loop, will run only 1 time, allows exit
   coorType 0 le {                                               % the default |
     /x2D x leftHanded not { neg } if Alpha cos mul y Alpha sin mul add def %  /\  co system
     /y2D x leftHanded { neg } if Alpha sin mul y Alpha cos mul add neg Beta sin mul z Beta cos mul add def
     exit } if
   coorType 1 le {
     /x2D y x Alpha 90 sub sin mul sub def  %  |/_  co system, no shortened x axis
     /y2D z x Alpha 90 sub cos mul sub def
     exit } if
   coorType 2 le { % coorType |/_ with a 1/sqrt(2) shortend x-axis and 135 degrees
     /x2D y x 0.5 mul sub def
     /y2D z x 0.5 mul sub def
     exit } if
   coorType 3 le { % coorType |/_ with a 1/sqrt(2) shortend x-axis and 135 degrees
     /x2D y x -0.5 mul sub def
     /y2D z x -0.5 mul sub def
     exit } if
   coorType 4 le { % Normalbild in Trimetrie Skalierung so, dass coorType2
      /x2D x -0.5 mul y 1 mul add def
      /y2D x -0.5 mul y -0.25 mul add z 1 mul add def
      exit } if
   coorType 5 le { % coorType |/_ with a 1/2 shortend x-axis and 135 degrees
     /x2D x z 0.5 mul Alpha cos mul add def
     /y2D y z 0.5 mul Alpha sin mul add def
     exit } if
   coorType 6 le { % coorType |/_ with a 1/2 shortend x-axis and 135 degrees and z into the front
     /x2D y x -0.559 mul Alpha cos mul add def
     /y2D z x -0.559 mul Alpha sin mul add def
     exit } if
   coorType 7 le { % coorType |/_ with a 1/2 shortend x-axis and 135 degrees and z into the front
     /x2D y x -0.5 mul Alpha cos mul add def
     /y2D z x -0.5 mul Alpha sin mul add def
     exit } if
 } repeat
} def
/ConvertTo2D { true 3Dto2D } def
/ConvertTo2DWithoutRotating { false 3Dto2D } def
%
/Conv3D2D { /z ED /y ED /x ED ConvertTo2D x2D y2D } def
%
/ConvertToCartesian {
 /latitude exch def
 /longitude exch def
 /Radius exch def
 1 { %  dummy loop, will run only 1 time, allows exit
   SphericalCoorType 0 le {                                               % the default |
    /z { Radius latitude sin mul } def
    /x { Radius longitude cos mul latitude cos mul } def
    /y { Radius longitude sin mul latitude cos mul } def
     exit } if
   SphericalCoorType 2 le {
    /z { Radius longitude cos mul } def
    /x { Radius longitude sin mul latitude cos mul} def
    /y { Radius longitude sin mul latitude sin mul } def
     exit } if
 } repeat
} def
%
/ConvCylToCartesian { % r phi h -> x y z
 3 1 roll                      % h r phi
 /Phi ED
 /Radius ED                    % h->z on stack
 Radius Phi cos mul exch       % x z
 Radius Phi sin mul exch       % x y z
} def
%
/SphericalTo2D {
 x y z ConvertToCartesian ConvertTo2D
} def
%
/CylinderTo2D { %  r phi h
 x y z ConvCylToCartesian ConvertTo2D
} def
%
/convertStackTo2D {
 counttomark
 /n ED /n3 n 3 div cvi def
 n3 {
   n -3 roll
   SphericalCoor { ConvertToCartesian } { saveCoor } ifelse
   ConvertTo2D
   x2D xUnit y2D yUnit
   /n n 1 sub def
 } repeat
} def
%
% the angle in the parameter equation for an ellipse is not proportional to the real angle!
% phi=atan(b*tan(angle)/a)+floor(angle/180+0.5)*180
%
/getPhi { % on stack: vecA vecB angle
 3 dict begin
 /angle exch def /vecB exch def /vecA exch def
 angle cvi 90 mod 0 eq { angle } { vecA angle tan mul vecB atan
 angle 180 div .5 add floor 180 mul add } ifelse
 end
} def
%
/RotSet (set ) def
%
/eulerRotation false def
% Matrix multiplication procedure
/matmul {

 /M@tMulDict 20 dict def
 M@tMulDict begin
 /m2 ED
 /m1 ED
 m1 dup length 2 sub 2 getinterval aload pop
 /col1max ED
 /row1max ED
 m2 dup length 2 sub 2 getinterval aload pop
 /col2max ED
 /row2max ED
 /m3 row1max col2max mul 2 add array def
 m3 dup length 2 sub row1max col2max 2 array astore putinterval
 0 1 row1max 1 sub {
  /row ED
  0 1 col2max 1 sub {
   /col ED
   /sum 0 def
   0 1 col1max 1 sub{
   /rowcol ED
   sum
   m1 row col1max mul rowcol add get
   m2 rowcol col2max mul col add get
   mul add
   /sum ED
   } for
   m3 row col2max mul col add sum put
  } for
 } for
 m3
 end % end of M@tMulDict

} def
%
/SetMQuaternion {

 /MnewTOold 11 array def

 /Qu@ternionDict 30 dict def
 Qu@ternionDict begin

 /normRotVec  xRotVec yRotVec zRotVec 3 array astore VecNorm  def
 normRotVec 0 gt
 {/xRotVecNorm xRotVec normRotVec div def
  /yRotVecNorm yRotVec normRotVec div def
  /zRotVecNorm zRotVec normRotVec div def
  RotAngle}
 {/xRotVecNorm 1 def
  /yRotVecNorm 0 def
  /zRotVecNorm 0 def
  0} ifelse

 2 div dup
 /q0 exch cos def
     sin dup dup
 /q1 exch xRotVecNorm mul def
 /q2 exch yRotVecNorm mul def
 /q3 exch zRotVecNorm mul def

 /q0q0 q0 q0 mul def
 /q0q1 q0 q1 mul def
 /q0q2 q0 q2 mul def
 /q0q3 q0 q3 mul def

 /q1q1 q1 q1 mul def
 /q1q2 q1 q2 mul def
 /q1q3 q1 q3 mul def

 /q2q2 q2 q2 mul def
 /q2q3 q2 q3 mul def

 /q3q3 q3 q3 mul def

 MnewTOold 0 q0q0 q1q1 add q2q2 sub q3q3 sub put
 MnewTOold 1 q1q2 q0q3 sub 2 mul put
 MnewTOold 2 q1q3 q0q2 add 2 mul put

 MnewTOold 3 q1q2 q0q3 add 2 mul put
 MnewTOold 4 q0q0 q1q1 sub q2q2 add q3q3 sub put
 MnewTOold 5 q2q3 q0q1 sub 2 mul put

 MnewTOold 6 q1q3 q0q2 sub 2 mul put
 MnewTOold 7 q2q3 q0q1 add 2 mul put
 MnewTOold 8 q0q0 q1q1 sub q2q2 sub q3q3 add put

 MnewTOold 9 3 put
 MnewTOold 10 3 put

 end % end of Qu@ternionDict

} def
%
/SetMxyz {
 1.0 0.0 0.0  0.0 1.0 0.0  0.0 0.0 1.0  3 3  11 array astore /MnewTOold ED
 RotSequence cvx exec % Now create a new MnewTOold using xyz, etc.
} def
%
/ConcatMQuaternion {
 MnewTOold % Push onto stack
 SetMQuaternion % Uses [xyz]RotVec and RotAngle to make MnewToOld
 MnewTOold matmul /MnewTOold ED
} def
%
/ConcatMxyz {
 MnewTOold % Push onto stack
 SetMxyz % Uses RotX, etc. to set MnewTOold
 MnewTOold matmul /MnewTOold ED
} def
%
/RotatePoint{
 MnewTOold x y z  3 1  5 array astore matmul
 0 3 getinterval aload pop
 /z ED
 /y ED
 /x ED
} def
%
/makeMoldTOnew {
 /MoldTOnew 11 array def
 MoldTOnew 0 MnewTOold 0 get put
 MoldTOnew 1 MnewTOold 3 get put
 MoldTOnew 2 MnewTOold 6 get put
 MoldTOnew 3 MnewTOold 1 get put
 MoldTOnew 4 MnewTOold 4 get put
 MoldTOnew 5 MnewTOold 7 get put
 MoldTOnew 6 MnewTOold 2 get put
 MoldTOnew 7 MnewTOold 5 get put
 MoldTOnew 8 MnewTOold 8 get put
 MoldTOnew 9               3 put
 MoldTOnew 10              3 put
} def
%
/RotXaxis {
 eulerRotation
 {1 0 0}
 {makeMoldTOnew MoldTOnew  1 0 0  3 1  5 array astore matmul
  0 3 getinterval aload pop} ifelse
 /zRotVec ED
 /yRotVec ED
 /xRotVec ED
 /RotAngle RotX def
 ConcatMQuaternion
} def
/RotYaxis {
 eulerRotation
 {0 1 0}
 {makeMoldTOnew MoldTOnew  0 1 0  3 1  5 array astore matmul
  0 3 getinterval aload pop} ifelse
 /zRotVec ED
 /yRotVec ED
 /xRotVec ED
 /RotAngle RotY def
 ConcatMQuaternion
} def
/RotZaxis {
 eulerRotation
 {0 0 1}
 {makeMoldTOnew MoldTOnew  0 0 1  3 1  5 array astore matmul
  0 3 getinterval aload pop} ifelse
 /zRotVec ED
 /yRotVec ED
 /xRotVec ED
 /RotAngle RotZ def
 ConcatMQuaternion
} def
/xyz { RotXaxis RotYaxis RotZaxis } def
/yxz { RotYaxis RotXaxis RotZaxis } def
/yzx { RotYaxis RotZaxis RotXaxis } def
/xzy { RotXaxis RotZaxis RotYaxis } def
/zxy { RotZaxis RotXaxis RotYaxis } def
/zyx { RotZaxis RotYaxis RotXaxis } def
/quaternion { } def % Null
%
/VecNorm { 0 exch { dup mul add } forall sqrt } def
%
/UnitVec {                      % on stack is [a]; returns a vector with [a][a]/|a|=1
 dup VecNorm /norm ED
 norm 0 lt {/norm 0 def} if
 { norm div } forall 3 array astore } def
%
/AxB {                          % on the stack are the two vectors [a][b]
   aload pop /b3 ED /b2 ED /b1 ED
   aload pop /a3 ED /a2 ED /a1 ED
   a2 b3 mul a3 b2 mul sub
   a3 b1 mul a1 b3 mul sub
   a1 b2 mul a2 b1 mul sub
   3 array astore } def
%
/AaddB {                        % on the stack are the two vectors [a][b]
   aload pop /b3 ED /b2 ED /b1 ED
   aload pop /a3 ED /a2 ED /a1 ED
   a1 b1 add a2 b2 add a3 b3 add
   3 array astore } def
%
/AmulC {                        % on stack is [a] and c; returns [a] mul c
   /factor ED { factor mul } forall 3 array astore } def
%
%
/setColorLight { % expects 7 values on stack C M Y K xL yL zL
% les rayons de lumi�re
 xLight dup mul yLight dup mul zLight dup mul add add sqrt /NormeLight ED
% the color values
 /K ED
 /Yellow ED
 /Magenta ED
 /Cyan ED
} def
%
/facetteSphere {
 newpath
 /Xpoint Rsphere theta cos mul phi cos mul CX add def
 /Ypoint Rsphere theta sin mul phi cos mul CY add def
 /Zpoint Rsphere phi sin mul CZ add def
 Xpoint Ypoint Zpoint tx@3Ddict begin ProjThreeD end moveto
 theta 1 theta increment add {%
   /theta1 ED
   /Xpoint Rsphere theta1 cos mul phi cos mul CX add def
   /Ypoint Rsphere theta1 sin mul phi cos mul CY add def
   /Zpoint Rsphere phi sin mul CZ add def
   Xpoint Ypoint Zpoint tx@3Ddict begin ProjThreeD end  lineto
 } for
 phi 1 phi increment add {
   /phi1 ED
   /Xpoint Rsphere theta increment add cos mul phi1 cos mul CX add def
   /Ypoint Rsphere theta increment add sin mul phi1 cos mul CY add def
   /Zpoint Rsphere phi1 sin mul CZ add def
   Xpoint Ypoint Zpoint tx@3Ddict begin ProjThreeD end lineto
 } for
 theta increment add -1 theta {%
   /theta1 ED
   /Xpoint Rsphere theta1 cos mul phi increment add cos mul CX add def
   /Ypoint Rsphere theta1 sin mul phi increment add cos mul CY add def
   /Zpoint Rsphere phi increment add sin mul CZ add def
   Xpoint Ypoint Zpoint tx@3Ddict begin ProjThreeD end lineto
 } for
 phi increment add -1 phi {
   /phi1 ED
   /Xpoint Rsphere theta cos mul phi1 cos mul CX add def
   /Ypoint Rsphere theta sin mul phi1 cos mul CY add def
   /Zpoint Rsphere phi1 sin mul CZ add def
   Xpoint Ypoint Zpoint tx@3Ddict begin ProjThreeD end lineto
 } for
 closepath
} def
%
/MaillageSphere {
% on stack must be x y z Radius increment C M Y K
 setColorLight
 /increment ED
 /Rsphere ED
 /CZ ED
 /CY ED
 /CX ED
 /StartTheta 0 def
 /condition { PSfacetteSphere 0 ge } def
 -90 increment 90 increment sub {%
   /phi ED
   StartTheta increment 360 StartTheta add increment sub {%
     /theta ED
     % Centre de la facette
     /Xpoint Rsphere theta increment 2 div add cos mul phi increment 2 div add cos mul CX add def
     /Ypoint Rsphere theta increment 2 div add sin mul phi increment 2 div add cos mul CY add def
     /Zpoint Rsphere phi increment 2 div add sin mul CZ add def
     % normale a la facette
     /nXfacette Xpoint CX sub def
     /nYfacette Ypoint CY sub def
     /nZfacette Zpoint CZ sub def
     % test de visibilite
     /PSfacetteSphere
       vX nXfacette mul
       vY nYfacette mul add
       vZ nZfacette mul add
     def
     condition {
       gsave
       facetteSphere
       /cosV { 1 xLight nXfacette mul
         yLight nYfacette mul
         zLight nZfacette mul
         add add
         NormeLight
         nXfacette dup mul
         nYfacette dup mul
         nZfacette dup mul
         add add sqrt mul div sub } bind def
       Cyan cosV mul Magenta cosV mul Yellow cosV mul K cosV mul setcmykcolor fill
       grestore
%       0 setgray
       showgrid { facetteSphere stroke } if
     } if
   } for
   % /StartTheta StartTheta increment 2 div add def
 } for
} def
%
%---------------------- Cylinder ---------------------------
%
/PlanCoupeCylinder { %
 /TableauxPoints [
   0 1 359 {
     /phi ED
     [ Radius phi Height ConvCyl2d ] % on décrit le cercle
   } for
 ] def
 newpath
 TableauxPoints 0 get aload pop moveto
 1 1 359 { TableauxPoints exch get aload pop lineto } for
 closepath
} def
%
/facetteCylinder { %
   newpath
   Radius phi currentHeight ConvCyl2d moveto
   phi 1 phi dAngle add  { % loop variable on stack
     Radius exch currentHeight ConvCyl2d lineto
   } for
   phi dAngle add -1 phi { %   fill dHeight
     Radius exch currentHeight dHeight add ConvCyl2d lineto
   } for
   closepath
 } def % facette
%
/MaillageCylinder { % on stack true or false for saving values
   { setColorLight  % expects 4 values on stack C M Y K
     /dHeight ED /dAngle ED /Height ED /Radius ED
     /CZ ED /CY ED /CX ED } if
%
   0 dHeight Height dHeight sub {
     /currentHeight ED
     0 dAngle 360 dAngle sub {
       /phi ED
% Normal vector of the center
       /nXfacetteCylinder Radius phi dAngle 2 div add cos mul CX add def
       /nYfacetteCylinder Radius phi dAngle 2 div add sin mul CY add def
       /nZfacetteCylinder currentHeight dHeight 2 div add CZ add def
       /NormeN
         nXfacetteCylinder dup mul
         nYfacetteCylinder dup mul
         nZfacetteCylinder dup mul
         add add sqrt def
       NormeN 0 eq { /NormeN 1e-10 def } if
% test de visibilité
      /PSfacetteCylinder
           vX nXfacetteCylinder mul
           vY nYfacetteCylinder mul add
           vZ nZfacetteCylinder mul add def
      condition {
        facetteCylinder
        /cosV
          1 xLight nXfacetteCylinder mul
          yLight nYfacetteCylinder mul
          zLight nZfacetteCylinder mul
          add add
          NormeLight NormeN mul div sub def
        Cyan Magenta Yellow K
        cosV mul 4 1 roll cosV mul 4 1 roll
        cosV dup mul mul 4 1 roll cosV dup mul mul 4 1 roll
        setcmykcolor fill
         showgrid {
           0 setgray
           facetteCylinder % drawing the segments
           stroke } if
      } if
    } for
   } for
} def
%
%------------------------ Cylinder type II -----------------------
%
/MoveTo { Conv3D2D moveto } def
/LineTo { Conv3D2D lineto } def

/IIIDEllipse { % x y z rA rB startAngle endAngle Wedge
 /dAngle 1 def
 /isWedge ED
 /endAngle ED
 /startAngle ED
 /radiusB ED
 /radiusA ED
 startAngle cos radiusA mul startAngle sin radiusB mul 0
 isWedge { 0 0 moveto LineTo }{ MoveTo } ifelse
 /Angle startAngle def
 startAngle dAngle endAngle {
   /Angle ED
   Angle cos radiusA mul Angle sin radiusB mul 0 LineTo
 } for
 isWedge { 0 0 lineto } if
} def

/IIIDCircle { % x y z r startAngle endAngle Wedge
 7 3 roll % startAngle endAngle Wedge x y z r
 dup      % startAngle endAngle Wedge x y z r r
 8 -3 roll
 IIIDEllipse
} def

/IIIDWedge { % x y z r startAngle endAngle
 true IIIDCircle
} def

/IIIDCylinder {% x y z r h start end wedge
 /isWedge ED
 /increment ED
 /endAngle ED
 /startAngle ED
 /height ED
 /radius ED
 startAngle increment endAngle {
   /Angle ED
   radius Angle 0 ConvCylToCartesian MoveTo
   radius Angle height ConvCylToCartesian LineTo
 } for
 stroke
} def
%
%---------------------- Box ---------------------------
%
/PlanCoupeBox { % x y z
 /TableauxPoints [
     [ CX CY CZ Height add ConvBox2d ] % top or bottom
     [ CX CY Depth add CZ Height add ConvBox2d ]
     [ CX Width add CY Depth add CZ Height add ConvBox2d ]
     [ CX Width add CY CZ Height add ConvBox2d ]
     [ CX CY CZ Height add ConvBox2d ] % bottom
   ] def
   newpath
   TableauxPoints 0 get aload pop moveto
   0 1 3 {
     TableauxPoints exch get aload pop
     lineto } for
   closepath
} def
%
/facetteBox { %
   newpath
   dup
   1 eq { % back
     CX CY CZ ConvBox2d moveto
     CX CY CZ Height add ConvBox2d lineto
     CX Width add CY CZ Height add ConvBox2d lineto
     CX Width add CY CZ ConvBox2d lineto
     CX CY CZ ConvBox2d lineto
   } if
   dup
   2 eq { % right
     CX CY CZ ConvBox2d moveto
     CX CY CZ Height add ConvBox2d lineto
     CX CY Depth add CZ Height add ConvBox2d lineto
     CX CY Depth add CZ ConvBox2d lineto
     CX CY CZ ConvBox2d lineto
   } if
   dup
   3 eq { % left
     CX Width add CY CZ ConvBox2d moveto
     CX Width add CY Depth add CZ ConvBox2d lineto
     CX Width add CY Depth add CZ Height add ConvBox2d lineto
     CX Width add CY CZ Height add ConvBox2d lineto
     CX Width add CY CZ ConvBox2d lineto
   } if
   4 eq { % front
     CX CY Depth add CZ ConvBox2d moveto
     CX CY Depth add CZ Height add ConvBox2d lineto
     CX Width add CY Depth add CZ Height add ConvBox2d lineto
     CX Width add CY Depth add CZ ConvBox2d lineto
     CX CY Depth add CZ ConvBox2d lineto
   } if
   closepath
 } def % facette
%
/TestPlane { % on stack x y z of the plane center and # of plane
 /nZfacetteBox ED /nYfacetteBox ED /nXfacetteBox ED
 /Plane ED
 /NormeN
   nXfacetteBox dup mul
   nYfacetteBox dup mul
   nZfacetteBox dup mul
   add add sqrt def
 NormeN 0 eq { /NormeN 1e-10 def } if
% test de visibilite
 /PSfacetteBox
   vX nXfacetteBox mul
   vY nYfacetteBox mul add
   vZ nZfacetteBox mul add def
 condition {
   Plane facetteBox
        /cosV
          1 xLight nXfacetteBox mul
          yLight nYfacetteBox mul
          zLight nZfacetteBox mul
          add add
          NormeLight NormeN mul div sub def
        Cyan Magenta Yellow K
        cosV mul 4 1 roll cosV mul 4 1 roll
        cosV dup mul mul 4 1 roll cosV dup mul mul 4 1 roll
        setcmykcolor fill
        0 setgray
        Plane facetteBox % drawing the segments
        stroke
      } if
} def
%
/MaillageBox { % on stack true or false for saving values
   { setColorLight  % expects 4 values on stack C M Y K
     /Depth ED /Height ED /Width ED
     /CZ ED /CY ED /CX ED } if
%
% Normal vector of the box center
 /PlaneSet [
   [ Width 2 div CX add
     CY
     Height 2 div CZ add ] % normal back
   [ CX
     Depth 2 div CY add
     Height 2 div CZ add ] % normal right
   [ Width CX add
     Depth 2 div CY add
     Height 2 div CZ add ] % normal left
   [ Width 2 div CX add
     Depth CY add
     Height 2 div CZ add ] % normal front
 ] def
 PlaneSequence length 0 eq { % user defined?
   Alpha abs cvi 360 mod /iAlpha ED
   iAlpha 90 lt { [ 1 2 3 4 ]
     }{ iAlpha 180 lt { [ 2 4 1 3 ]
       }{ iAlpha 270 lt { [ 3 4 1 2 ] }{ [ 3 1 4 2] } ifelse } ifelse } ifelse
 }{ PlaneSequence } ifelse
 { dup 1 sub PlaneSet exch get aload pop TestPlane } forall
} def
%
%--------------------------- Paraboloid -----------------------------
/PlanCoupeParaboloid {
   /Z height store
   /V {Z sqrt} bind def
   /TableauxPoints [
     0 1 359 {
       /U ED [ U U Z V calculate2DPoint ] % on decrit le cercle
     } for
   ] def
   newpath
   TableauxPoints 0 get aload pop moveto
   0 1 359 {
     /compteur ED
     TableauxPoints compteur get aload pop
     lineto } for
   closepath
} def
%
/facetteParaboloid{
   newpath
   U U Z V calculate2DPoint moveto
   U 1 U increment add  {%
     /U1 ED
     U1 U1 Z V calculate2DPoint lineto
   } for
   Z pas10 Z pas add pas10 add{
     /Z1 ED
     /V {Z1 sqrt} bind def
     U1 U1 Z1 V calculate2DPoint lineto
   } for
   U increment add -1 U {%
     /U2 ED
     U2 U2 Z pas add V calculate2DPoint lineto
   } for
   Z pas add pas10 sub pas10 neg Z pas10 sub {
     /Z2 ED
     /V Z2 abs sqrt def
     U U Z2 V calculate2DPoint lineto
   } for
   closepath
} def % facette
%
/MaillageParaboloid {
 % on stack true or false for saving values
   { setColorLight  % expects 7 values on stack C M Y K xL yL zL
%      /CZ ED /CY ED /CX ED
   } if
   0 pas height pas sub {%
     /Z ED
     /V Z sqrt def
     0 increment 360 increment sub {%
       /U ED
% Centre de la facette
       /Ucentre U increment 2 div add def
       /Vcentre Z pas 2 div add sqrt def
% normale à la facette
       /nXfacetteParaboloid 2 Vcentre dup mul mul Ucentre cos mul radius mul def
       /nYfacetteParaboloid 2 Vcentre dup mul mul Ucentre sin mul radius mul def
       /nZfacetteParaboloid Vcentre neg radius dup mul mul def
       /NormeN {
         nXfacetteParaboloid dup mul
         nYfacetteParaboloid dup mul
         nZfacetteParaboloid dup mul
         add add sqrt} bind def
       NormeN 0 eq {/NormeN 1e-10 def} if
% test de visibilit�
      /PSfacetteParaboloid vX nXfacetteParaboloid mul
                 vY nYfacetteParaboloid mul add
                 vZ nZfacetteParaboloid mul add def
      condition {
        facetteParaboloid
        /cosV 1 xLight nXfacetteParaboloid mul
          yLight nYfacetteParaboloid mul
          zLight nZfacetteParaboloid mul
          add add
          NormeLight
          NormeN mul div sub def
        Cyan Magenta Yellow K
        cosV mul 4 1 roll cosV mul 4 1 roll cosV dup mul mul 4 1 roll cosV dup mul mul 4 1 roll
        setcmykcolor fill
        showgrid {
          0 setgray
          facetteParaboloid
          stroke } if
      } if
    } for
   } for
} def
%
% ------------------------------------ math stuff ----------------------------------
%
% Matrix A in arrays of rows A[[row1][row2]...]
% with [row1]=[a11 a12 ... b1]
% returns on stack solution vector X=[x1 x2 ... xn]
/SolveLinEqSystem {                             % on stack matrix M=[A,b] (A*x=b)
 10 dict begin                                 % hold all ocal
   /A exch def
   /Rows A length def                          % Rows = number of rows
   /Cols A 0 get length def                    % Cols = number of columns
   /Index [ 0 1 Rows 1 sub { } for ] def       % Index = [0 1 2 ... Rows-1]
   /col 0 def
   /row  0 def
   /PR Rows array def                          % PR[c] = pivot row for row row
 {                                             % starts the loop, find pivot entry in row r
   col Cols ge row  Rows ge or { exit } if     % col < Cols and row < Rows else exit
   /pRow row def                               % pRow = pivot row
   /max A row  get col get abs def             % get A[row[col]], first A[0,0]
   row 1 add 1 Rows 1 sub {                    % starts for loop 1 1 Rows-1
     /j exch def                               % index counter
     /x A j get col get abs def                % get A[j[r]]
     x max gt {                                % x>max, then save position
       /pRow j def
       /max x def
     } if
   } for                                       % now we have the row with biggest A[0,1]
                                               % with pRow = the pivot row
   max 0 gt {                                  % swap entries pRow and row  in i
     /tmp Index row  get def
     Index row  Index pRow get put
     Index pRow tmp put                        % and columns pRow and row  in A
     /tmp A row get def
     A row  A pRow get put
     A pRow tmp put                            % pivot
     /row0  A row  get def                     % the pivoting row
     /p0 row0  col get def                     % the pivot value
     row 1 add 1 Rows 1 sub {                  % start for loop
       /j exch def
       /c1 A j get def
       /p c1 col get p0 div def
       c1 col p put                            % subtract (p1/p0)*row[i] from row[j]
       col 1 add 1 Cols 1 sub {                % start for loop
         /i exch def
         c1 dup i exch                         % c1 i c1
         i get row0 i get p mul sub put
       } for
     } for
     PR row col put
     /col col 1 add def
     /row row 1 add def
   }{                                          % all zero entries
     /row row 1 add def                        % continue loop with same row
   } ifelse
 } loop
 /X A def                                      % solution vector
 A Rows 1 sub get dup
 Cols 1 sub get exch
 Cols 2 sub get div
 X Rows 1 sub 3 -1 roll put                    % X[n]
 Rows 2 sub -1 0 {                             % for loop to calculate X[i]
   /xi exch def                                % current index
   A xi get                                    % i-th row
   /Axi exch def
   /sum 0 def
   Cols 2 sub -1 xi 1 add {
     /n exch def
     /sum sum Axi n get X n get mul add def
   } for
   Axi Cols 1 sub get                          % b=Axi[Cols-1]
   sum sub                                     % b-sum
   Axi xi get div                              % b-sum / Axi[xi]
   X xi 3 -1 roll put                          % X[xi]
 } for
 X
 end
} def
%
% u -> e_u with |e_u|=1
/vector-unit { 1 dict begin
 dup vector-length 1 exch div
 vector-scale
 end
} def
%
% u v -> u+v
/vector-add { 1 dict begin
 /v exch def
 [ exch
 0             % u i
 exch {        % i u[i]
   v           % i u[i] v
   2 index get add     % i u[i]+v[i]
   exch 1 add  % i
 } forall
 pop
 ]
 end
} def
%
% u v -> u-v
/vector-sub { 1 dict begin
 /v exch def
 [ exch
 0             % u i
 exch {        % i u[i]
   v           % i u[i] v
   2 index get sub     % i u[i]+v[i]
   exch 1 add  % i
 } forall
 pop
 ]
end } def
%
% [v] c -> [c.v]
/vector-scale { 1 dict begin
 /c exch def
 [ exch
 {             % s i u[i]
   c mul       % s i u[i] v
 } forall
 ]
 end } def
%
%
% [u] [v] -> [u x v]
/vector-prod { %% x1 y1 z1 x2 y2 z2
6 dict begin
 aload pop
 /zp exch def /yp exch def /xp exch def
 aload pop
 /z exch def /y exch def /x exch def
 [ y zp mul z yp mul sub
  z xp mul x zp mul sub
  x yp mul y xp mul sub ]
end
} def
%
% [u] [v] -> u.v
/vector-mul { %% x1 y1 z1 x2 y2 z2
6 dict begin
 aload pop
 /zp exch def /yp exch def /xp exch def
 aload pop
 /z exch def /y exch def /x exch def
 x xp mul y yp mul add z zp mul add
end
} def
%
% [x y z ... ] -> r
% watch out for overflow
/vector-length { 1 dict begin
dup
% find maximum entry
/max 0 def
{ % max
 abs dup max gt {
   % if abs gt max
   /max exch def
 } {
   pop
 } ifelse
} forall
max 0 ne {
 0 exch
 {  % 0 v[i]
   max div dup mul add
 } forall
 sqrt
 max mul
} {
 pop 0
} ifelse
end } def
%
end % tx@3DPlotDict
%