(* :Mathematica Version: Mathematica 3.0 *)

(* :Name: Graphics`ParametricPlot3D` *)

(* :Context: Graphics`ParametricPlot3D` *)

(* :Title: Parametric Plots of 3D Objects *)

(* :Author:
	Roman E. Maeder
*)

(* :Copyright: Copyright 1991-1999, Wolfram Research, Inc. *)

(* :Package Version: 2.0 *)

(* :History:
    V1.0 by Roman Maeder
    V2.0 fix option handling -- John M. Novak, September 1998
*)

(* :Keywords:
	Parametric, Spherical, Cylindrical Plot, 3D
*)

(* :Requirements: None. *)

(* :Warnings: None. *)

(* :Sources: 
        Adapted from
        Roman E. Maeder: Programming in Mathematica,
        Third Edition, Addison-Wesley, 1996.
*)

(* :Summary:
This package allows one to specify the step size of the grid
used by ParametricPlot3D.  In contrast, the built-in function
ParametricPlot3D requires that the grid be specified using the
option PlotPoints.  The package also introduces the functions
PointParametricPlot3D, SphericalPlot3D, and CylindricalPlot3D.
*)


BeginPackage["Graphics`ParametricPlot3D`"]

Unprotect[PointParametricPlot3D, SphericalPlot3D, CylindricalPlot3D]

If[StringPosition[ParametricPlot3D::usage, "increments"] === {},

ParametricPlot3D::usage = ParametricPlot3D::usage <> " " <>
"ParametricPlot3D[{x,y,z,(style)}, {u,u0,u1,du}, ({v,v0,v1,dv})]
uses increments du and dv instead of the PlotPoints option."

]

PointParametricPlot3D::usage =
"PointParametricPlot3D[{x,y,z}, {u,u0,u1,(du)}, (options)]
plots a one-parameter set of points in space.
PointParametricPlot3D[{x,y,z}, {u,u0,u1,(du)}, {v,v0,v1,(dv)}, (options)]
plots a two-parameter set of points in space. Options are passed to Show."

SphericalPlot3D::usage =
"SphericalPlot3D[r, {theta, thetamin, thetamax}, {phi, phimin, phimax},
(options)] plots r as a function of the angles theta and phi.
SphericalPlot3D[{r, style}, ...] uses style to render each surface patch."

CylindricalPlot3D::usage =
"CylindricalPlot3D[z, {r, rmin, rmax}, {phi, phimin, phimax}, (options)]
plots z as a function of r and phi.
CylindricalPlot3D[{z, style},  ...] uses style to render each surface patch."

Begin["`Private`"]

protected = Unprotect[ParametricPlot3D]

Needs["Utilities`FilterOptions`"]

(* overload ParametricPlot3D to allow increments in iterators *)

ParametricPlot3D[ fun_, {u_, u0_, u1_, du_:Automatic}, {v_, v0_, v1_, dv_:Automatic}, opts___?OptionQ ] :=
	Module[{plotpoints},
		plotpoints = PlotPoints /. {opts} /. Options[ParametricPlot3D];
		If[ Head[plotpoints] =!= List, plotpoints = {plotpoints, plotpoints} ];
		If[ du =!= Automatic, plotpoints[[1]] = Round[(u1-u0)/du] + 1 ];
		If[ dv =!= Automatic, plotpoints[[2]] = Round[(v1-v0)/dv] + 1 ];
		ParametricPlot3D[ fun, {u, u0, u1}, {v, v0, v1}, PlotPoints -> plotpoints, opts]
	]  /; du =!= Automatic || dv =!= Automatic

ParametricPlot3D[ fun_, {u_, u0_, u1_, du_}, opts___?OptionQ ] :=
	ParametricPlot3D[ fun, {u, u0, u1}, PlotPoints -> Round[(u1-u0)/du] + 1, opts]


Attributes[PointParametricPlot3D] = {HoldFirst}

Options[PointParametricPlot3D] =
    {PlotPoints -> Automatic} ~Join~ Options[Graphics3D];

PointParametricPlot3D[ fun_, {u_, u0_?NumericQ, u1_?NumericQ, du_:Automatic},
		{v_, v0_?NumericQ, v1_?NumericQ, dv_:Automatic}, opts___?OptionQ ] :=
	Module[{plotpoints, ndu = N[du], ndv = N[dv]},
		plotpoints = PlotPoints /.
                    Flatten[{opts, Options[PointParametricPlot3D]}];
		If[ plotpoints === Automatic, plotpoints = 15];
		If[ Head[plotpoints] =!= List, plotpoints = {plotpoints, plotpoints} ];
		If[ du === Automatic, ndu = N[(u1-u0)/(plotpoints[[1]]-1)] ];
		If[ dv === Automatic, ndv = N[(v1-v0)/(plotpoints[[2]]-1)] ];
		Show[ Graphics3D[Table[ Point[N[fun]], {u, u0, u1, ndu}, {v, v0, v1, ndv} ]],
		      FilterOptions[Graphics3D,
                             Flatten[{opts, Options[PointParametricPlot3D]}]] ]
	]

(* point space curve *)

PointParametricPlot3D[ fun_, ul:{_, u0_?NumericQ, u1_?NumericQ, du_?NumericQ}, opts___?OptionQ ] :=
	Show[ Graphics3D[Table[ Point[N[fun]], ul ]],
             FilterOptions[Graphics3D,
                 Flatten[{opts, Options[PointParametricPlot3D]}]] ]

PointParametricPlot3D[ fun_, {u_, u0_, u1_}, opts___?OptionQ ] :=
    Module[{plotpoints},
    	plotpoints = PlotPoints /.
            Flatten[{opts, Options[PointParametricPlot3D]}];
        If[plotpoints === Automatic, plotpoints = 15];
    	If[ Head[plotpoints] == List, plotpoints = plotpoints[[1]] ];
	PointParametricPlot3D[ fun, {u, u0, u1, (u1-u0)/(plotpoints-1)}, opts ]
    ]


Options[SphericalPlot3D] = Options[ParametricPlot3D];

Attributes[SphericalPlot3D] = {HoldFirst}

SphericalPlot3D[ {r_, style_}, tlist:{theta_, __}, plist:{phi_, __}, opts___?OptionQ ] :=
	Module[{rs},
		ParametricPlot3D[ {(rs = r) Sin[theta] Cos[phi],
		                   rs Sin[theta] Sin[phi],
		                   rs Cos[theta],
		                   style},
		                  tlist, plist, ## ]& @@
                {FilterOptions[ParametricPlot3D,
                     Flatten[{opts, Options[SphericalPlot3D]}]]}
	]

SphericalPlot3D[ r_, tlist:{theta_, __}, plist:{phi_, __}, opts___?OptionQ ] :=
      ParametricPlot3D[ r{Sin[theta] Cos[phi],
                          Sin[theta] Sin[phi],
                          Cos[theta]},
                        tlist, plist, ## ] & @@
      {FilterOptions[ParametricPlot3D,
                     Flatten[{opts, Options[SphericalPlot3D]}]]}


Options[CylindricalPlot3D] = Options[ParametricPlot3D];

Attributes[CylindricalPlot3D] = {HoldFirst}

CylindricalPlot3D[ {z_, style_}, rlist:{r_, __}, plist:{phi_, __}, opts___?OptionQ ] :=
	ParametricPlot3D[{r Cos[phi], r Sin[phi], z, style}, rlist, plist, ##]& @@
            {FilterOptions[ParametricPlot3D,
                     Flatten[{opts, Options[CylindricalPlot3D]}]]}

CylindricalPlot3D[ z_, rlist:{r_, __}, plist:{phi_, __}, opts___?OptionQ ] :=
	ParametricPlot3D[{r Cos[phi], r Sin[phi], z}, rlist, plist, ##]& @@
            {FilterOptions[ParametricPlot3D,
                     Flatten[{opts, Options[CylindricalPlot3D]}]]}

Protect[ Evaluate[protected] ]

End[]

Protect[PointParametricPlot3D, SphericalPlot3D, CylindricalPlot3D]

EndPackage[]

Null

(* :Examples:

ParametricPlot3D[{x, y, x y}, {x, -1, 1, 0.2}, {y, -1, 1}];
ParametricPlot3D[{x, y, x y}, {x, -1, 1, 0.2}, {y, -1, 1}, PlotPoints -> 20];
ParametricPlot3D[{x, y, x y}, {x, -1, 1, 0.2}, {y, -1, 1}, PlotPoints -> {20,20}];

ParametricPlot3D[{Cos[t], Sin[t], t/6}, {t, 0, 4Pi, Pi/12}];

CylindricalPlot3D[ r^2, {r,0,1}, {phi,0,2 Pi}]

CylindricalPlot3D[ r^2, {r,0,1}, {phi,-Pi/4,5 Pi/4},
   Boxed -> False, ViewPoint ->{1.3,-2.4,1.6} ]

SphericalPlot3D[ Sin[theta]^2, {theta,0,Pi}, {phi,0,3 Pi/2}]

CylindricalPlot3D[ 1.5 Sqrt[1+r^2], {r,0,2}, {phi, 0, 2Pi}]

ParametricPlot3D[ { Cosh[z] Cos[phi], Cosh[z] Sin[phi], z },
   {z, -2, 2}, {phi, 0, 2 Pi} ]

*)
