-- $Date: 2004/02/23 08:22:06 $
-- $Revision: 1.20 $
-- $Author: jcrocholl $

-- with Messages; use Messages;

package body Cubics is

   -- Create a cubic bezier curve.
   function Create
     (To        : in Vector-- End point of the curve.
      Control_A : in Vector-- First control point of curve.
      Control_B : in Vector-- Second control point of curve.
     return Line_Access is   -- The newly created curve.
   begin
      return new Cubic'(To => To,
        Control_A => Control_A,
        Control_B => Control_B,
        Length => 0.0);
   end Create;

   -- Calculate the arc length of this curve. Results are cached for
   -- reuse. So make sure the starting point always remains the same
   -- between calls.
   function Length
     (Start : in Vector;    -- Starting point of the curve.
      This  : access Cubic-- Get this curve's arc length.
     return Real is         -- The length of the arc.
   begin
      if This.Length = 0.0 then
         This.Length := abs(This.To - Start);
      end if;
      return This.Length;
   end Length;

   -- Scale a curve by a given factor.
   procedure Scale
     (This   : access Cubic-- Scale this curve.
      Factor : in Real) is   -- Scaling factor.
   begin
      This.To := This.To * Factor;
      This.Control_A := This.Control_A * Factor;
      This.Control_B := This.Control_B * Factor;
      This.Length := This.Length * Factor;
   end Scale;

   -- Translate a curve by a given offset.
   procedure Translate
     (This   : access Cubic-- Translate this curve.
      Offset : in Vector) is -- Translating offset.
   begin
      This.To := This.To + Offset;
      This.Control_A := This.Control_A + Offset;
      This.Control_B := This.Control_B + Offset;
   end Translate;

   -- Get one point from the cubic bezier curve.
   function Way_Point
     (Start : in Vector;    -- Starting point of the curve.
      This  : access Cubic-- Definition of the curve.
      Part  : in Real)      -- Parametrization variable from 0 to 1.
     return Vector          -- The point on the curve.
   is
      Part_1 : Real := 1.0 - Part;
   begin
      return Start * Cube(Part_1) +
        This.Control_A * 3.0 * Square(Part_1) * Part +
        This.Control_B * 3.0 * Part_1 * Square(Part) +
        This.To * Cube(Part);
   end Way_Point;

   -- Format a cubic bezier curve for Scalable Vector Graphics output.
   function To_SVG
     (This      : access Cubic-- Format this curve.
      Tolerance : in Real)      -- Tolerance level.
     return String is           -- The resulting SVG code.
   begin
      return "C " &
        To_String(This.Control_A, Tolerance) & " " &
        To_String(This.Control_B, Tolerance) & " " &
        To_String(This.To, Tolerance);
   end To_SVG;

   -- Format a cubic bezier curve for postscript output.
   function To_Postscript
     (This      : access Cubic-- Format this curve.
      Tolerance : in Real)      -- Tolerance level.
     return String is           -- The resulting Postscript code.
   begin
      return
        To_String(Mirror_Y(This.Control_A), Tolerance) & " " &
        To_String(Mirror_Y(This.Control_B), Tolerance) & " " &
        To_String(Mirror_Y(This.To), Tolerance) & " curveto";
   end To_Postscript;

end Cubics;