-- $Date: 2004/01/10 11:43:46 $
-- $Revision: 1.6 $
-- $Author: jcrocholl $

with Messages; use Messages;
with Outlines; use Outlines;
with Lines; use Lines;
with Cubics; use Cubics;
with Real_Vectors; use Real_Vectors;

package body Curves is

   -- Join straight lines into cubic bezier curves, if the distance
   -- between original and joined lines remains below tolerance.
   procedure Make_Cubic
     (This      : in out Outline-- Make curves in this outline.
      Tolerance : in Real)        -- Maximum distance to the joined line.
   is
      use Line_Lists;
      Item_1  : Item := Last_Item(This);
      Item_2  : Item := First_Item(This);
      Item_3  : Item := Next_Item(Item_2);
      Item_4  : Item := Next_Item(Item_3);
      Stop    : Item := Item_3;
      Counter : Natural := 2;

      Line_1, Line_2, Line_3, Line_4 : Line;

      procedure Content is
      begin
         -- Debug2("1");
         Line_1 := Item_Content(Item_1);
         -- Debug2("2");
         Line_2 := Item_Content(Item_2);
         -- Debug2("3");
         Line_3 := Item_Content(Item_3);
         -- Debug2("4");
         Line_4 := Item_Content(Item_4);
         -- Debug(Integer'Image(Counter) &
         -- Integer'Image(Line_Lists.Count(This)) &
         -- ' ' & To_String(Line_1.To) & ' ' & To_String(Line_2.To) &
         -- ' ' & To_String(Line_3.To) & ' ' & To_String(Line_4.To));
      end Content;

      procedure Valid_2 is
      begin
         if Item_Invalid(Item_2) then
            Item_2 := First_Item(This);
         end if;
      end Valid_2;

      procedure Valid_4 is
      begin
         if Item_Invalid(Item_4) then
            Item_4 := First_Item(This);
            Counter := 0;
         end if;
      end Valid_4;

      procedure Half_Step is
      begin
         Counter := Counter + 1;
         Item_3 := Item_4;
         Item_4 := Next_Item(Item_4);
         Valid_4;
         -- Debug("Half_Step");
         Content;
      end Half_Step;

      procedure Step is
      begin
         Item_1 := Item_2;
         Item_2 := Item_3;
         -- Debug2("Step+");
         Half_Step;
      end Step;

      Curve_23 : Line-- Cubic bezier joining Item_3 with Item_2.
      Curve_34 : Line-- Cubic bezier joining Item_3 with Item_2.
      Error_23 : Real-- Error when joining Item_3 with Item_2.
      Error_34 : Real-- Error when joining Item_3 with Item_4.
   begin
      -- Debug("new border");
      Content;
      while Line_Lists.Count(This) > 2 loop
         -- Try to join Item_3 with Item_2 or Item_4.
         Make_Cubic(Line_1.To, Line_2, Line_3, Curve_23, Error_23);
         Make_Cubic(Line_2.To, Line_3, Line_4, Curve_34, Error_34);
         if Error_23 <= Tolerance and Error_23 < Error_34 then
            Update_Item(Item_3, Line(Curve_23)); -- Join Item_2 into Item_3.
            Remove_Item(Item_1, Item_2, This); -- Remove and advance Item_2.
            Valid_2; -- Wrap around end of list.
            Half_Step; -- Advance Item_3 and Item_4.
            Stop := Item_3; -- Set iteration stopper.
         elsif Error_34 <= Tolerance then
            Update_Item(Item_3, Line(Curve_34)); -- Join Item_4 into Item_3.
            Remove_Item(Item_3, Item_4, This); -- Remove and advance Item_4.
            Valid_4; -- Wrap around end of list.
            Step; -- Advance all.
            Stop := Item_3; -- Set iteration stopper.
         end if;

         Step;
         exit when Item_Equals(Item_3, Stop);
      end loop;
   end Make_Cubic;

   -- Join straight lines into cubic bezier curves, if the distance
   -- between original and joined lines remains below tolerance.
   procedure Make_Cubic
     (This      : in Glyph-- Make curves in this glyph.
      Tolerance : in Real)  -- Maximum distance to the joined line.
   is
      use Glyphs.Outline_Lists;
      Outlines        : Outline_List;
      Current_Outline : Outline;
   begin
      -- Debug2("make cubic... ");
      Outlines := Get_Outlines(This);
      Reset(Outlines);
      while Next(Outlines) loop
         Current_Outline := Current(Outlines);
         Make_Cubic(Current_Outline, Tolerance);
      end loop;
      -- Debug(Character'Val(13) & "make cubic done. ");
   end Make_Cubic;

end Curves;