\section{Specific and Interpolated Curves} \begin{code}
module RSAGL.Math.CurveExtras
(sphericalCoordinates,
cylindricalCoordinates,
toroidalCoordinates,
circularCoordinates,
polarCoordinates,
transformUnitSquareToUnitCircle,
transformUnitCubeToUnitSphere,
circleXY,
regularPolygon,
linearInterpolation,
loopedLinearInterpolation,
smoothCurve,
loopCurve)
where

import RSAGL.Math.Curve
import RSAGL.Math.Interpolation
import RSAGL.Math.Vector
import RSAGL.Math.Angle
import RSAGL.Math.AbstractVector
import RSAGL.Math.Affine
import RSAGL.Math.ListUtils
import Control.Arrow
import RSAGL.Math.Types

\end{code} \subsection{Alternate Coordinate Systems for Models} \begin{code}
sphericalCoordinates :: ((Angle,Angle) -> a) -> Surface a
sphericalCoordinates f = transformSurface2 id (clampCurve (0,1)) $surface$ curry (f . (\(u,v) -> (fromRadians $u*2*pi,fromRadians$ ((pi/2) - v*pi))))

cylindricalCoordinates :: ((Angle,RSdouble) -> a) -> Surface a
cylindricalCoordinates f = transformSurface2 id (clampCurve (0,1)) $surface$ curry (f . (\(u,v) -> (fromRadians $u*2*pi,v))) toroidalCoordinates :: ((Angle,Angle) -> a) -> Surface a toroidalCoordinates f = surface$ curry (f . (\(u,v) -> (fromRadians $u*2*pi,fromRadians$ negate $v*2*pi))) circularCoordinates :: ((RSdouble,RSdouble) -> a) -> Surface a circularCoordinates f = surface$ curry $(f . second negate . transformUnitSquareToUnitCircle) polarCoordinates :: ((Angle,RSdouble) -> a) -> Surface a polarCoordinates f = circularCoordinates (f . cartesianToPolar)  \end{code} \subsection{Transformations Between Unit Volumes} \begin{code} transformUnitSquareToUnitCircle :: (RSdouble,RSdouble) -> (RSdouble,RSdouble) transformUnitSquareToUnitCircle (u,v) = (x,z) where (Point3D x _ z) = transformUnitCubeToUnitSphere (Point3D u 0.5 v) transformUnitCubeToUnitSphere :: Point3D -> Point3D transformUnitCubeToUnitSphere p = let p_centered@(Point3D x y z) = scale' 2.0$ translate (Vector3D (-0.5) (-0.5) (-0.5)) p
p_projected = scale' (minimum [recip $abs x,recip$ abs y,recip $abs z]) p_centered k = recip$ distanceBetween origin_point_3d p_projected
w = maximum $[abs x, abs y, abs z] -- 'w' could be 1, but this gives a smoother tesselation in if p_centered == origin_point_3d then origin_point_3d else lerp w (p_centered,scale' k p_centered)  \end{code} \subsection{Circles} \begin{code} circleXY :: Curve Point3D circleXY = curve$ \u_ -> let u = fromRotations u_ in Point3D (cosine u) (sine u) 0

\end{code} \subsection{Regular Polygons} A regular polygon, centered at the origin, in the XY plane. \begin{code}
regularPolygon :: Integer -> Curve Point3D
regularPolygon n = loopedLinearInterpolation $map (flip rotateZ (Point3D 0 1 0) . fromRotations)$ zeroToOne n

\end{code} \subsection{Piecewise Length Normalization} \begin{code}
normalizePolyline :: (AbstractSubtract p v,AbstractMagnitude v) => [p] -> [(RSdouble,p)]
normalizePolyline pts = zip (map (/ total_dist) accumulated_dists) pts
where dists = map (uncurry abstractDistance) $doubles pts total_dist = last accumulated_dists accumulated_dists = scanl (+) 0 dists  \end{code} \subsection{Interpolated Curves} \begin{code} linearInterpolation :: (AbstractSubtract p v,AbstractAdd p v,AbstractMagnitude v,AbstractScale v) => [p] -> Curve p linearInterpolation = curve . lerpMap . normalizePolyline loopedLinearInterpolation :: (AbstractSubtract p v,AbstractAdd p v,AbstractMagnitude v,AbstractScale v) => [p] -> Curve p loopedLinearInterpolation = loopCurve (0,1) . linearInterpolation . (\a -> last a:a)  \end{code} \subsection{Smoothing Curves} \texttt{smoothCurve i h} takes i samples of an h-long piece of a 'Curve' at each point to smooth it. This is not an interpolation function and will tend to shrink shapes toward their center of gravity. \begin{code} smoothCurve :: (AbstractAdd p v,AbstractSubtract p v,AbstractVector v,AbstractZero p) => Integer -> RSdouble -> Curve p -> Curve p smoothCurve i h c = curve$ \u -> abstractAverage $iterateCurve i$ controlCurve (u-h/2,u+h/2) (0,1) c

\end{code}