----------------------------------------------- --------------------------------- -- -- -- OCARINA COMPONENTS -- -- -- -- O C A R I N A . D I A . P R I N T E R . O P T I M I Z E -- -- -- -- B o d y -- -- -- -- Copyright (C) 2005-2007, GET-Telecom Paris. -- -- -- -- Ocarina is free software; you can redistribute it and/or modify -- -- it under terms of the GNU General Public License as published by the -- -- Free Software Foundation; either version 2, or (at your option) any -- -- later version. Ocarina is distributed in the hope that it will be -- -- useful, but WITHOUT ANY WARRANTY; without even the implied warranty of -- -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -- -- Public License for more details. You should have received a copy of the -- -- GNU General Public License distributed with Ocarina; see file COPYING. -- -- If not, write to the Free Software Foundation, 51 Franklin Street, Fifth -- -- Floor, Boston, MA 02111-1301, USA. -- -- -- -- As a special exception, if other files instantiate generics from this -- -- unit, or you link this unit with other files to produce an executable, -- -- this unit does not by itself cause the resulting executable to be -- -- covered by the GNU General Public License. This exception does not -- -- however invalidate any other reasons why the executable file might be -- -- covered by the GNU Public License. -- -- -- -- Ocarina is maintained by the Ocarina team -- -- (ocarina-users@listes.enst.fr) -- -- -- ------------------------------------------------------------------------------ -- This package contains the top-level procedures to optimize the -- position of the objects in the Dia file with Ada.Text_IO; use Ada.Text_IO; with DOM.Core; with DOM.Core.Nodes; with DOM.Core.Documents; -- Using the parser stuff to avoid duplicating the source with Ocarina.Dia.Parser.Core; with Ocarina.Dia.Parser.Core.Attributes; with Ocarina.Dia.Parser.Core.Diagram; with Ocarina.Dia.Parser.Core.Nodes; with Ada.Numerics.Elementary_Functions; use Ada.Numerics.Elementary_Functions; package body Ocarina.Dia.Printer.Optimize is -- Translates the XML Document to a compound graph -- for optimization function XML_To_Graph (Doc : DOM.Core.document) return compound_graph is use Ocarina.Dia; Document : constant DOM.Core.node := DOM.Core.Documents.Get_Element (Doc); NL : constant Ocarina.Dia.Parser.Core.node_list := Parser.Core.Diagram.Process_Diagram (Document); N : Parser.Core.node; S : Unbounded_String; Nat : Natural; Num_Objects : constant Integer := Parser.Core.Count_Objects (NL); Num_Links : constant Integer := Parser.Core.Nodes.Length (NL) - Num_Objects; Null_Point : constant Printer.Misc.point := (0.0, 0.0); Null_Rectangle : constant Printer.Misc.rectangle := (Null_Point, Null_Point); Num_Ports : Natural; Num_Connections : Natural; Ports : point_array_ptr; G : compound_graph; Big_Boss : constant graph_node := new graph_node_record' (ID => 0, Dia_ID => To_Unbounded_String ("Ze Big Boss"), Position => Null_Point, Width => 0.0, Height => 0.0, BBox => Null_Rectangle, Parent => 0, Text => To_Unbounded_String (""), Text_Pos => Null_Point, Ports => null, Num_Ports => 0); GN : graph_node; E : edge; Obj_Cpt : Natural := 1; Lnk_Cpt : Natural := 1; function Port_To_ID (P : Natural; NP : Natural) return Natural; function Port_To_ID (P : Natural; NP : Natural) return Natural is begin if P <= 2 * NP then return (P / 2) + 1; else return P + 1 - NP; end if; end Port_To_ID; begin Put_Line ("Translating XML to Graph"); Put_Line ("Number of Objects : " & Integer'image (Num_Objects)); Put_Line ("Number of Links : " & Integer'image (Num_Links)); -- We add an arbitrary root object, index 0, that contains -- every orphan node G.Nodes := new graph_node_array (0 .. Num_Objects); G.Edges := new adjacent_graph (1 .. Num_Links); -- There are as many inclusion edges as objects (except the -- big one), because every object has exactly one parent G.Hierarchy := new inclusion_graph (1 .. Num_Objects); -- Filling in the graph... G.Nodes (0) := Big_Boss; for I in 0 .. Parser.Core.Nodes.Length (NL) - 1 loop Put_Line ("Creating node n° " & Integer'image (I)); N := NL.Items (I); Num_Ports := Parser.Core.Nodes.Count_Ports (N); Num_Connections := Parser.Core.Nodes.Count_Connections (N); case N.Node_Type_Arg is when Parser.Core.aadlobject_type => Put_Line ("=> This is object n° " & Integer'image (Obj_Cpt)); if To_String (N.Parent) = "" then S := Big_Boss.Dia_ID; Nat := 0; else S := N.Parent; -- Works because a parent is always -- defined *before* a child for J in 0 .. Obj_Cpt - 1 loop declare N2 : constant graph_node := G.Nodes (J); begin if N2.Dia_ID = S then Nat := J; end if; end; end loop; end if; Ports := new point_array (1 .. (Num_Ports + Num_Connections)); for I in 1 .. Num_Ports loop Ports (I) := Null_Point; end loop; for I in 1 .. Num_Connections loop Ports (Num_Ports + I) := Null_Point; end loop; GN := new graph_node_record' (ID => Obj_Cpt, Dia_ID => N.ID, Position => Null_Point, Width => 0.0, Height => 0.0, BBox => Null_Rectangle, Parent => Nat, Text => N.Name, Text_Pos => Null_Point, Ports => Ports, Num_Ports => Num_Ports); E := new edge_record' (Dia_ID => To_Unbounded_String (""), First => N.ID, First_Int => GN.ID, First_Port => -1, Second => S, Second_Int => Nat, Second_Port => -1); G.Nodes (Obj_Cpt) := GN; G.Hierarchy (Obj_Cpt) := E; Obj_Cpt := Obj_Cpt + 1; when Parser.Core.link => Put_Line ("=> This is link n° " & Integer'image (Lnk_Cpt)); E := new edge_record' (Dia_ID => N.ID, First => N.Conn.Start_Point.Object_ID, First_Int => 0, First_Port => N.Conn.Start_Point.Port, Second => N.Conn.End_Point.Object_ID, Second_Int => 0, Second_Port => N.Conn.End_Point.Port); G.Edges (Lnk_Cpt) := E; Lnk_Cpt := Lnk_Cpt + 1; when others => -- Will never happen null; end case; end loop; -- Resolve the integers in edges for I in 1 .. Num_Links loop E := G.Edges (I); for J in 1 .. Num_Objects loop GN := G.Nodes (J); if E.First = GN.Dia_ID then E.First_Int := J; E.First_Port := Port_To_ID (E.First_Port, GN.Num_Ports); end if; if E.Second = GN.Dia_ID then E.Second_Int := J; E.Second_Port := Port_To_ID (E.Second_Port, GN.Num_Ports); end if; end loop; end loop; return G; end XML_To_Graph; -- Updates a single dia:attribute procedure Update_Attribute (NL : in out DOM.Core.node_list; Obj_Name : String; Attr_Name : String; Value : String) is use Ocarina.Dia; N2 : DOM.Core.node; P : Natural := 0; Attrs : DOM.Core.named_node_map; begin Put_Line ("> Updating attribute " & Obj_Name); N2 := Parser.Core.Attributes.Get_Attribute_Node (NL, Obj_Name); Parser.Core.Get_Required_Child (DOM.Core.Nodes.Child_Nodes (N2), Attr_Name, P, N2); Attrs := DOM.Core.Nodes.Attributes (N2); DOM.Core.Nodes.Set_Node_Value (DOM.Core.Nodes.Get_Named_Item (Attrs, "val"), Value); end Update_Attribute; -- Updates an arrow's connection points procedure Update_Arrow_Points (NL : in out DOM.Core.node_list; Value1 : String; Value2 : String) is use Ocarina.Dia; N : DOM.Core.node; N2 : DOM.Core.node; P : Natural := 0; Attrs : DOM.Core.named_node_map; begin Put_Line ("> Updating arrow points"); N := Parser.Core.Attributes.Get_Attribute_Node (NL, "conn_endpoints"); Parser.Core.Get_Required_Child (DOM.Core.Nodes.Child_Nodes (N), "dia:point", P, N2); Attrs := DOM.Core.Nodes.Attributes (N2); DOM.Core.Nodes.Set_Node_Value (DOM.Core.Nodes.Get_Named_Item (Attrs, "val"), Value1); P := P + 1; Parser.Core.Get_Required_Child (DOM.Core.Nodes.Child_Nodes (N), "dia:point", P, N2); Attrs := DOM.Core.Nodes.Attributes (N2); DOM.Core.Nodes.Set_Node_Value (DOM.Core.Nodes.Get_Named_Item (Attrs, "val"), Value2); end Update_Arrow_Points; -- Updates an object's ports' positions procedure Update_Ports (NL : in out DOM.Core.node_list; Vect : Printer.Misc.point; Values : point_array_ptr) is use Ocarina.Dia; N : DOM.Core.node; N2 : DOM.Core.node; P : Natural := 0; Compteur : Natural := Values'first; NL2 : DOM.Core.node_list; New_P : point; begin Put_Line ("> Updating " & Integer'image (Values'last) & " ports"); N := Parser.Core.Attributes.Get_Attribute_Node (NL, "aadlbox_ports"); while Compteur <= Values'last loop Parser.Core.Get_Required_Child (DOM.Core.Nodes.Child_Nodes (N), "dia:composite", P, N2); Put_Line ("Vect : " & Printer.Misc.Print_Point (Vect)); New_P := Values (Compteur); Put_Line ("RelPos : " & Printer.Misc.Print_Point (New_P)); New_P.X := New_P.X + Vect.X; New_P.Y := New_P.Y + Vect.Y; Put_Line ("AbsPos : " & Printer.Misc.Print_Point (New_P)); NL2 := DOM.Core.Nodes.Child_Nodes (N2); Update_Attribute (NL2, "point", "dia:point", Printer.Misc.Print_Point (New_P)); Compteur := Compteur + 1; P := P + 1; end loop; end Update_Ports; -- Updates an object's connection points procedure Update_Connection_Points (NL : in out DOM.Core.node_list; Vect : Printer.Misc.point; Values : point_array_ptr) is use Ocarina.Dia; N : DOM.Core.node; N2 : DOM.Core.node; P : Natural := 0; Compteur : Natural := Values'first; Attrs : DOM.Core.named_node_map; New_P : point; begin Put_Line ("> Updating " & Integer'image (Values'last) & " connection points"); N := Parser.Core.Attributes.Get_Attribute_Node (NL, "aadlbox_connections"); while Compteur <= Values'last loop Parser.Core.Get_Required_Child (DOM.Core.Nodes.Child_Nodes (N), "dia:point", P, N2); New_P := Values (Compteur); New_P.X := New_P.X + Vect.X; New_P.Y := New_P.Y + Vect.Y; Attrs := DOM.Core.Nodes.Attributes (N2); DOM.Core.Nodes.Set_Node_Value (DOM.Core.Nodes.Get_Named_Item (Attrs, "val"), Printer.Misc.Print_Point (New_P)); Compteur := Compteur + 1; P := P + 1; end loop; end Update_Connection_Points; -- Updates the XML Document with the new contents -- of the Graph (both must correspond) procedure Graph_To_XML (Doc : DOM.Core.document; Graph : compound_graph) is use Ocarina.Dia; Document : constant DOM.Core.node := DOM.Core.Documents.Get_Element (Doc); CL : DOM.Core.node_list := DOM.Core.Nodes.Child_Nodes (Document); N : DOM.Core.node; NL : DOM.Core.node_list; P : Natural := 0; Id : Unbounded_String; Obj_Cpt : Natural := 1; Lnk_Cpt : Natural := 1; GN : graph_node; E : edge; Pos : point; T : point; Rect : rectangle; Absolute_Pos : array (0 .. Graph.Nodes'last) of point; Ports : point_array_ptr; Connections : point_array_ptr; begin Parser.Core.Get_Required_Child (CL, "dia:layer", P, N); CL := DOM.Core.Nodes.Child_Nodes (N); Put_Line ("Updating XML view from Graph..."); N := DOM.Core.Nodes.First_Child (N); Absolute_Pos (0) := (X => 0.0, Y => 0.0); while N /= null loop if Obj_Cpt <= Graph.Nodes'last then GN := Graph.Nodes (Obj_Cpt); end if; if Lnk_Cpt <= Graph.Edges'last then E := Graph.Edges (Lnk_Cpt); end if; if N.Node_Type = DOM.Core.element_node and then DOM.Core.Nodes.Node_Name (N) = "dia:object" then Put ("Updating object : "); NL := DOM.Core.Nodes.Child_Nodes (N); Id := To_Unbounded_String (Parser.Core.Get_Required_Attribute (DOM.Core.Nodes.Attributes (N), "id")); if Id = GN.Dia_ID then Put_Line ("node " & To_String (Id)); -- Computing the data Put_Line ("> Computing the data..."); T := Absolute_Pos (GN.Parent); Pos.X := GN.Position.X + T.X; Pos.Y := GN.Position.Y + T.Y; Absolute_Pos (Obj_Cpt) := (X => Pos.X, Y => Pos.Y); Rect.TL.X := GN.BBox.TL.X + T.X; Rect.TL.Y := GN.BBox.TL.Y + T.Y; Rect.BR.X := GN.BBox.BR.X + T.X; Rect.BR.Y := GN.BBox.BR.Y + T.Y; -- And dumping it Update_Attribute (NL, "obj_pos", "dia:point", Printer.Misc.Print_Point (Pos)); Update_Attribute (NL, "elem_corner", "dia:point", Printer.Misc.Print_Point (Pos)); Update_Attribute (NL, "elem_width", "dia:real", Float'image (GN.Width)); Update_Attribute (NL, "elem_height", "dia:real", Float'image (GN.Height)); Update_Attribute (NL, "obj_bb", "dia:rectangle", Printer.Misc.Print_Rectangle (Rect)); -- Translates all ports and connection points -- since they are bound the object Ports := new point_array (1 .. GN.Num_Ports); Connections := new point_array (1 .. GN.Ports'last - GN.Num_Ports); for I in 1 .. GN.Num_Ports loop Ports (I) := GN.Ports (I); end loop; for I in 1 .. (GN.Ports'last - GN.Num_Ports) loop Connections (I) := GN.Ports (GN.Num_Ports + I); end loop; Update_Ports (NL, Absolute_Pos (Obj_Cpt), Ports); Update_Connection_Points (NL, Absolute_Pos (Obj_Cpt), Connections); -- And last but not least, changing the textbox position -- Caution : overwrites the NL variable, so should be done -- last Put_Line ("> Updating textbox"); P := 0; declare N2 : DOM.Core.node; begin N2 := Parser.Core.Attributes.Get_Attribute_Node (NL, "name"); Parser.Core.Get_Required_Child (DOM.Core.Nodes.Child_Nodes (N2), "dia:composite", P, N2); NL := DOM.Core.Nodes.Child_Nodes (N2); Pos.X := GN.Text_Pos.X + T.X; Pos.Y := GN.Text_Pos.Y + T.Y; Update_Attribute (NL, "pos", "dia:point", Printer.Misc.Print_Point (Pos)); exception when others => null; end; Obj_Cpt := Obj_Cpt + 1; else if Id = To_String (E.Dia_ID) then Put_Line ("link " & To_String (Id)); -- Computing the data Pos := Absolute_Pos (E.First_Int); T := Absolute_Pos (E.Second_Int); Pos.X := Pos.X + Graph.Nodes (E.First_Int).Ports (E.First_Port).X; Pos.Y := Pos.Y + Graph.Nodes (E.First_Int).Ports (E.First_Port).Y; T.X := T.X + Graph.Nodes (E.Second_Int).Ports (E.Second_Port).X; T.Y := T.Y + Graph.Nodes (E.Second_Int).Ports (E.Second_Port).Y; Rect.TL := Pos; Rect.BR := T; -- And putting it back into the tree Update_Attribute (NL, "obj_pos", "dia:point", Printer.Misc.Print_Point (Pos)); Update_Attribute (NL, "obj_bb", "dia:rectangle", Printer.Misc.Print_Rectangle (Rect)); Update_Arrow_Points (NL, Printer.Misc.Print_Point (Pos), Printer.Misc.Print_Point (T)); Lnk_Cpt := Lnk_Cpt + 1; else Put ("Graph_To_XML has been called"); Put_Line (" on incompatible arguments."); raise Incompatible_Arguments; end if; end if; end if; N := DOM.Core.Nodes.Next_Sibling (N); end loop; end Graph_To_XML; -- Optimization of the graph layout procedure Optimize (Graph : in out compound_graph) is begin Optimize_Node (Graph, Graph.Nodes'first); end Optimize; procedure Optimize_Node (Graph : in out compound_graph; I : Natural) is P : edge; N : Natural := 0; List_Childs : list_nat := null; Is_Child : boolean_array (Graph.Nodes'first .. Graph.Nodes'last); Is_Child2 : boolean_array (Graph.Nodes'first .. Graph.Nodes'last); Num_Child : natural_array (Graph.Nodes'first .. Graph.Nodes'last); begin -- Compute the BBox, width and height of the Childs for J in Is_Child'first .. Is_Child'last loop Is_Child (J) := False; Is_Child2 (J) := False; Num_Child (J) := 0; end loop; -- Put_Line ("Optimization of " & To_String (Graph.Nodes (I).Dia_ID)); for J in Graph.Hierarchy'first .. Graph.Hierarchy'last loop P := Graph.Hierarchy (J); if I = P.Second_Int then Optimize_Node (Graph, P.First_Int); Add (List_Childs, P.First_Int); Is_Child (P.First_Int) := True; Is_Child2 (P.First_Int) := True; N := N + 1; Num_Child (P.First_Int) := N; end if; end loop; -- Put_Line (Natural'Image (N) & " childrens"); -- Put the childs at a right place. declare R_Width : Float := 0.0; R_Height : Float := 0.0; L : list_nat := List_Childs; T : graph_node; X : Float; Y : Float; Current : Natural; Value : float_array (1 .. N); -- L_One_Neighbour_Set : List_Nat := null; Occurences : float_array (1 .. N); Signe : Float := 1.0; begin -- Compute the length of the axes of the ellipse while L /= null loop T := Graph.Nodes (L.H); R_Width := R_Width + T.Width; R_Height := R_Height + T.Height; L := L.Q; end loop; -- Put_Line ("ellipse axes computed"); L := Copy_List (List_Childs); -- Compute the value of the Childs. for J in 1 .. N loop Value (J) := 0.0; Occurences (J) := 0.0; end loop; -- At this point, Value is the max of connections for J in Graph.Edges'first .. Graph.Edges'last loop if Is_Child (Graph.Edges (J).First_Int) then if Is_Child (Graph.Edges (J).Second_Int) then Value (Num_Child (Graph.Edges (J).Second_Int)) := Value (Num_Child (Graph.Edges (J).Second_Int)) + 1.0; Value (Num_Child (Graph.Edges (J).First_Int)) := Value (Num_Child (Graph.Edges (J).First_Int)) + 1.0; end if; end if; end loop; -- Put_Line ("value of Child computed"); if L /= null then -- first position R_Height := (R_Height / 6.0) + (0.75 * Float (N)); R_Width := (R_Width / 4.0) + (0.75 * Float (N)); Put_Line ("RW : " & Float'image (R_Width) & " RH : " & Float'image (R_Height)); X := 2.0; Y := R_Height * (1.0 + Signe * Sqrt ((1.0 - Pow ((X - 2.0) / R_Width - 1.0, 2)))); -- We place the Child of highest value. Current := Highest (Value); Put_Line ("value : " & Float'image (Value (Current))); Current := Element_Index (List_Childs, N - Current); Remove (L, Current); Is_Child (Current) := False; Value (Current) := -1.0; Graph.Nodes (Current).Position.X := X; Graph.Nodes (Current).Position.Y := Y; -- debug -- Put_Line ("Position of " & -- To_String (Graph.Nodes (Current).Dia_ID) & -- " : " & Float'Image (X) & " , " & Float'Image (Y)); X := X + Signe * ((Graph.Nodes (Current).Width) + 3.0); -- fin debug if X > (2.0 * R_Width + 2.0) then Signe := -Signe; X := 2.0 * R_Width; end if; Y := R_Height * (1.0 + Signe * Sqrt ((1.0 - Pow ((X - 2.0) / R_Width - 1.0, 2)))); -- Put_Line ("First Child placed"); end if; while L /= null loop for J in 1 .. N loop Occurences (J) := 0.0; end loop; declare A : Natural; B : Natural; -- Compute the neighbours of List_Chides.H -- and the number of connections between -- them. begin for J in Graph.Edges'first .. Graph.Edges'last loop A := Graph.Edges (J).First_Int; B := Graph.Edges (J).Second_Int; if Is_Child (A) then A := Num_Child (A); if B = Current then Occurences (A) := Occurences (A) + 1.0; end if; end if; if Is_Child (B) then B := Num_Child (B); if A = Current then Occurences (B) := Occurences (B) + 1.0; end if; end if; end loop; end; -- Select the next neighbour. Current := Highest (Occurences); -- Put_Line ("occurences : " & Float'Image -- (Occurences (Current))); if Occurences (Current) = 0.0 then Current := Highest (Value); end if; -- Put_Line ("value : " & Float'Image (Value (Current))); Value (Current) := -1.0; Current := Element_Index (List_Childs, N - Current); -- TODO : chose a better neigbour (using Value AND Occurences) -- Place the next neighbour. Remove (L, Current); Is_Child (Current) := False; if Signe < 0.0 then X := X + Signe * ((Graph.Nodes (Current).Width) + 3.0); if X < 2.0 then X := 2.0; end if; end if; Graph.Nodes (Current).Position.X := X; Y := R_Height * (1.0 + Signe * Sqrt ((1.0 - Pow ((X - 2.0) / R_Width - 1.0, 2)))); if Signe < 0.0 then Y := Y + Graph.Nodes (Current).Height + 1.0; end if; Graph.Nodes (Current).Position.Y := Y; -- Put_Line ("Position of " & -- To_String (Graph.Nodes (Current).Dia_ID) & -- " : " & Float'Image (X) & " , " & Float'Image (Y)); if Signe > 0.0 then X := X + Signe * ((Graph.Nodes (Current).Width) + 3.0); if X > (2.0 * R_Width + 2.0) then Signe := -Signe; X := 2.0 * R_Width + 2.0; end if; end if; -- if Signe < 0.0 then -- X := X - 3.0; -- end if; end loop; end; -- Compute the BBox, width and height of Node I declare Width_Max : Float; Height_Max : Float; W : Float; H : Float; L : list_nat := List_Childs; T : graph_node; begin Width_Max := 0.0; Height_Max := 0.0; while L /= null loop T := Graph.Nodes (L.H); W := T.Position.X + T.Width; H := T.Position.Y + T.Height; if W > Width_Max then Width_Max := W; end if; if H > Height_Max then Height_Max := H; end if; L := L.Q; end loop; Width_Max := Width_Max + 4.0; Height_Max := Height_Max + 2.0; -- Warnings : check if these values are correct Graph.Nodes (I).Width := Max (Width_Max, 10.0); Graph.Nodes (I).Height := Height_Max; Graph.Nodes (I).BBox := ((0.0, 0.0), (Width_Max, Height_Max)); -- TODO : free List_Childs -- Free_List (List_Childs); -- TODO : place connextions and ports end; if Graph.Nodes (I).Ports /= null then for J in Graph.Nodes (I).Ports'first .. Graph.Nodes (I).Ports'last loop Graph.Nodes (I).Ports (J) := (0.0, 0.0); end loop; end if; declare Pos1 : Boolean; Pos2 : Boolean; P1 : point; P2 : point; P3 : point; A : Natural; B : Natural; begin for J in Graph.Edges'first .. Graph.Edges'last loop A := Graph.Edges (J).First_Int; B := Graph.Edges (J).Second_Int; P1 := (Graph.Nodes (A).Position.X, Graph.Nodes (A).Position.Y + Graph.Nodes (A).Height); P2 := (Graph.Nodes (A).Position.X + Graph.Nodes (A).Width, Graph.Nodes (A).Position.Y); P3 := (Graph.Nodes (A).Position.X + Graph.Nodes (A).Width, Graph.Nodes (A).Position.Y + Graph.Nodes (A).Height); if Is_Child2 (A) and then Is_Child2 (B) then Pos1 := Is_Up (Graph.Nodes (A).Position, P3, Graph.Nodes (B).Position); Pos2 := Is_Up (P1, P2, Graph.Nodes (B).Position); Put_Line ("A" & Natural'image (A)); Put_Line ("B" & Natural'image (B)); Put_Line ("A1" & Natural'image (Graph.Edges (J).First_Port)); Put_Line ("B1" & Natural'image (Graph.Edges (J).Second_Port)); if Pos1 then if Pos2 then -- Bottom Graph.Nodes (A).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (A).Width / 2.0, Graph.Nodes (A).Height); Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (B).Width / 2.0, 0.0); else -- Left Graph.Nodes (A).Ports (Graph.Edges (J).First_Port) := (0.0, Graph.Nodes (A).Height / 2.0); Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (B).Width, Graph.Nodes (B).Height / 2.0); end if; else if Pos2 then -- Right Graph.Nodes (A).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (A).Width, Graph.Nodes (A).Height / 2.0); Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port) := (0.0, Graph.Nodes (B).Height / 2.0); else -- Up Graph.Nodes (A).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (A).Width / 2.0, 0.0); Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (B).Width / 2.0, Graph.Nodes (B).Height); end if; end if; end if; if Is_Child2 (A) and then not Is_Child2 (B) then if Graph.Nodes (A).Position.Y > Graph.Nodes (B).Height / 2.0 then if Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port).X = 0.0 and then Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port).Y = 0.0 then Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (A).Position.X + Graph.Nodes (A).Width / 2.0, Graph.Nodes (B).Height); end if; if Graph.Nodes (A).Ports (Graph.Edges (J).First_Port).X = 0.0 and then Graph.Nodes (A).Ports (Graph.Edges (J).First_Port).Y = 0.0 then Graph.Nodes (A).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (A).Width / 2.0, Graph.Nodes (A).Height); end if; else if Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port).X = 0.0 and then Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port).Y = 0.0 then Graph.Nodes (B).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (A).Position.X + Graph.Nodes (A).Width / 2.0, 0.0); end if; if Graph.Nodes (A).Ports (Graph.Edges (J).First_Port).X = 0.0 and then Graph.Nodes (A).Ports (Graph.Edges (J).First_Port).Y = 0.0 then Graph.Nodes (A).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (A).Width / 2.0, 0.0); end if; end if; end if; if Is_Child2 (B) and then not Is_Child2 (A) then if Graph.Nodes (B).Position.Y > Graph.Nodes (A).Height / 2.0 then if Graph.Nodes (A).Ports (Graph.Edges (J).Second_Port).X = 0.0 and then Graph.Nodes (A).Ports (Graph.Edges (J).Second_Port).Y = 0.0 then Graph.Nodes (A).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (B).Position.X + Graph.Nodes (B).Width / 2.0, Graph.Nodes (A).Height); end if; if Graph.Nodes (B).Ports (Graph.Edges (J).First_Port).X = 0.0 and then Graph.Nodes (B).Ports (Graph.Edges (J).First_Port).Y = 0.0 then Graph.Nodes (B).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (B).Width / 2.0, Graph.Nodes (B).Height); end if; else if Graph.Nodes (A).Ports (Graph.Edges (J).Second_Port).X = 0.0 and then Graph.Nodes (A).Ports (Graph.Edges (J).Second_Port).Y = 0.0 then Graph.Nodes (A).Ports (Graph.Edges (J).Second_Port) := (Graph.Nodes (B).Position.X + Graph.Nodes (B).Width / 2.0, 0.0); end if; if Graph.Nodes (B).Ports (Graph.Edges (J).First_Port).X = 0.0 and then Graph.Nodes (B).Ports (Graph.Edges (J).First_Port).Y = 0.0 then Graph.Nodes (B).Ports (Graph.Edges (J).First_Port) := (Graph.Nodes (B).Width / 2.0, 0.0); end if; end if; end if; end loop; end; end Optimize_Node; procedure Add (L : in out list_nat; I : in Integer) is begin L := new list_element'(I, L); end Add; function Is_Up (P : point; P1 : point; P2 : point) return Boolean is T : Float; begin T := (P1.X - P.X) * (P2.Y - P.Y) - (P1.Y - P.Y) * (P2.X - P.X); Put_Line (Float'image (T)); if T > 0.0 then return True; else return False; end if; end Is_Up; function Highest (A : float_array) return Natural is T : Float := -1.0; I : Natural := 1; begin for J in A'first .. A'last loop -- Put_Line (Float'Image (A (J))); if A (J) > T then T := A (J); I := J; end if; end loop; return I; end Highest; function Max (A : Float; B : Float) return Float is begin if A > B then return A; else return B; end if; end Max; function Copy_List (L : list_nat) return list_nat is begin if L = null then return null; else return new list_element'(L.H, Copy_List (L.Q)); end if; end Copy_List; procedure Remove (L : in out list_nat; I : Integer) is begin if L /= null then if L.H = I then L := L.Q; else Remove (L.Q, I); end if; end if; end Remove; function Element_Index (L : list_nat; I : Integer) return Natural is begin if L /= null then if I = 0 then return L.H; else return Element_Index (L.Q, I - 1); end if; end if; Put_Line ("Element Not Found"); return Natural'last; end Element_Index; function Pow (F : Float; I : Integer) return Float is begin if I = 0 then return 1.0; else return F * Pow (F, I - 1); end if; end Pow; -- procedure Free_List (L : in out List_Nat) is -- begin -- if L /= null then -- Free_List (L.Q); -- Free (L); -- end if; -- end Free_List; -- (Debug) Prints a graph to the stdo procedure Dump_Graph (G : compound_graph) is GN : graph_node; E : edge; begin Put_Line ("##########################"); Put_Line ("Dumping graph begins... "); Put_Line ("Graph Nodes :"); for I in 1 .. G.Nodes'last loop GN := G.Nodes (I); Put_Line ("-----------------------"); Put_Line ("Node n° " & Natural'image (GN.ID)); Put_Line ("Dia_ID : " & To_String (GN.Dia_ID)); Put_Line ("Position : " & Print_Point (GN.Position)); Put_Line ("Width : " & Float'image (GN.Width) & " Height : " & Float'image (GN.Height)); Put_Line ("Bounding Box : " & Print_Rectangle (GN.BBox)); Put_Line ("Parent : " & Natural'image (GN.Parent)); Put_Line ("Text : " & To_String (GN.Text) & " at " & Print_Point (GN.Position)); Put_Line ("Number of ports :" & Natural'image (GN.Num_Ports)); Put_Line ("Number of connections :" & Natural'image (GN.Ports'length - GN.Num_Ports)); end loop; Put_Line (""); Put_Line ("Edges :"); for I in 1 .. G.Edges'last loop E := G.Edges (I); Put_Line ("-----------------------"); Put_Line ("Edge n° " & Natural'image (I)); Put_Line ("Dia_ID : " & To_String (E.Dia_ID)); Put_Line ("Start : " & To_String (E.First) & ", n° " & Natural'image (E.First_Int) & " at anchor n° " & Integer'image (E.First_Port) & " located at " & Print_Point (G.Nodes (E.First_Int).Ports (E.First_Port))); Put_Line ("End : " & To_String (E.Second) & ", n° " & Natural'image (E.Second_Int) & " at anchor n° " & Integer'image (E.Second_Port) & " located at " & Print_Point (G.Nodes (E.Second_Int).Ports (E.Second_Port))); end loop; Put_Line ("###########################"); end Dump_Graph; end Ocarina.Dia.Printer.Optimize;