1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
26 gboolean gts_allow_floating_gnodes
= FALSE
;
28 static void gnode_remove_container (GtsContainee
* i
, GtsContainer
* c
)
30 (* GTS_CONTAINEE_CLASS (GTS_OBJECT_CLASS (gts_gnode_class ())->parent_class
)->remove_container
) (i
, c
);
31 if (GTS_SLIST_CONTAINEE (i
)->containers
== NULL
&&
32 !gts_allow_floating_gnodes
&&
33 !GTS_OBJECT_DESTROYED(GTS_OBJECT (i
)))
34 gts_object_destroy (GTS_OBJECT (i
));
37 static void gnode_class_init (GtsGNodeClass
* klass
)
41 GTS_CONTAINEE_CLASS (klass
)->remove_container
= gnode_remove_container
;
44 static void gnode_init (GtsGNode
* n
)
52 * Returns: the #GtsGNodeClass.
54 GtsGNodeClass
* gts_gnode_class (void)
56 static GtsGNodeClass
* klass
= NULL
;
59 GtsObjectClassInfo gnode_info
= {
62 sizeof (GtsGNodeClass
),
63 (GtsObjectClassInitFunc
) gnode_class_init
,
64 (GtsObjectInitFunc
) gnode_init
,
69 gts_object_class_new (GTS_OBJECT_CLASS (gts_slist_container_class ()),
78 * @klass: a #GtsGNodeClass.
80 * Returns: a new #GtsGNode.
82 GtsGNode
* gts_gnode_new (GtsGNodeClass
* klass
)
86 object
= GTS_GNODE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
92 * gts_gnode_foreach_neighbor:
94 * @g: a #GtsGraph or %NULL.
96 * @data: user data to be passed to @func.
98 * Calls @func for each neighbor #GtsGNode of @n (belonging to @g if
101 void gts_gnode_foreach_neighbor (GtsGNode
* n
,
108 g_return_if_fail (n
!= NULL
);
109 g_return_if_fail (func
!= NULL
);
111 i
= GTS_SLIST_CONTAINER (n
)->items
;
113 GtsGNode
* n1
= GTS_GNODE_NEIGHBOR (n
, i
->data
);
114 if (g
== NULL
|| gts_containee_is_contained (GTS_CONTAINEE (n1
),
122 * gts_gnode_foreach_edge:
124 * @g: a #GtsGraph or %NULL.
126 * @data: user data to be passed to @func.
128 * Calls @func for each #GtsGEdge connecting @n to another #GtsGNode
129 * (belonging to @g if @g is not %NULL.
131 void gts_gnode_foreach_edge (GtsGNode
* n
,
138 g_return_if_fail (n
!= NULL
);
139 g_return_if_fail (func
!= NULL
);
141 i
= GTS_SLIST_CONTAINER (n
)->items
;
143 GtsGNode
* n1
= GTS_GNODE_NEIGHBOR (n
, i
->data
);
144 if (g
== NULL
|| gts_containee_is_contained (GTS_CONTAINEE (n1
),
146 (* func
) (i
->data
, data
);
154 * @g: a #GtsGraph or %NULL.
156 * Returns: the number of neighbors of @n (belonging to @g if @g is not %NULL).
158 guint
gts_gnode_degree (GtsGNode
* n
,
164 g_return_val_if_fail (n
!= NULL
, 0);
166 i
= GTS_SLIST_CONTAINER (n
)->items
;
168 GtsGNode
* n1
= GTS_GNODE_NEIGHBOR (n
, i
->data
);
169 if (g
== NULL
|| gts_containee_is_contained (GTS_CONTAINEE (n1
),
179 * gts_gnode_move_cost:
181 * @src: a #GtsGraph containing @n.
182 * @dst: another #GtsGraph.
184 * Returns: the cost (increase in the sum of the weights of the edges cut) of
185 * moving @n from @src to @dst.
187 gfloat
gts_gnode_move_cost (GtsGNode
* n
,
194 g_return_val_if_fail (n
!= NULL
, G_MAXFLOAT
);
195 g_return_val_if_fail (src
!= NULL
, G_MAXFLOAT
);
196 g_return_val_if_fail (dst
!= NULL
, G_MAXFLOAT
);
197 g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n
),
198 GTS_CONTAINER (src
)),
201 i
= GTS_SLIST_CONTAINER (n
)->items
;
203 GtsGEdge
* ge
= i
->data
;
204 GtsGNode
* neighbor
= GTS_GNODE_NEIGHBOR (n
, ge
);
206 if (gts_containee_is_contained (GTS_CONTAINEE (neighbor
),
207 GTS_CONTAINER (src
)))
208 cost
+= gts_gedge_weight (ge
);
209 else if (gts_containee_is_contained (GTS_CONTAINEE (neighbor
),
210 GTS_CONTAINER (dst
)))
211 cost
-= gts_gedge_weight (ge
);
222 * Returns: the weight of @n as defined by the weight() method of the
225 gfloat
gts_gnode_weight (GtsGNode
* n
)
227 g_return_val_if_fail (n
!= NULL
, 0.);
229 if (GTS_GNODE_CLASS (GTS_OBJECT (n
)->klass
)->weight
)
230 return (* GTS_GNODE_CLASS (GTS_OBJECT (n
)->klass
)->weight
) (n
);
236 static void ngnode_init (GtsNGNode
* n
)
244 * Returns: the #GtsNGNodeClass.
246 GtsNGNodeClass
* gts_ngnode_class (void)
248 static GtsNGNodeClass
* klass
= NULL
;
251 GtsObjectClassInfo ngnode_info
= {
254 sizeof (GtsNGNodeClass
),
255 (GtsObjectClassInitFunc
) NULL
,
256 (GtsObjectInitFunc
) ngnode_init
,
257 (GtsArgSetFunc
) NULL
,
260 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
269 * @klass: a #GtsNGNodeClass.
271 * Returns: a new #GtsNGNode with identity @id.
273 GtsNGNode
* gts_ngnode_new (GtsNGNodeClass
* klass
,
278 n
= GTS_NGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass
)));
286 static gfloat
wgnode_weight (GtsGNode
* n
)
288 return GTS_WGNODE (n
)->weight
;
291 static void wgnode_class_init (GtsWGNodeClass
* klass
)
293 GTS_GNODE_CLASS (klass
)->weight
= wgnode_weight
;
296 static void wgnode_init (GtsWGNode
* n
)
304 * Returns: the #GtsWGNodeClass.
306 GtsWGNodeClass
* gts_wgnode_class (void)
308 static GtsWGNodeClass
* klass
= NULL
;
311 GtsObjectClassInfo wgnode_info
= {
314 sizeof (GtsWGNodeClass
),
315 (GtsObjectClassInitFunc
) wgnode_class_init
,
316 (GtsObjectInitFunc
) wgnode_init
,
317 (GtsArgSetFunc
) NULL
,
320 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
329 * @klass: a #GtsWGNodeClass.
330 * @weight: the weight of the #GtsWGNode to create.
332 * Returns: a new #GtsWGNode of weight @weight.
334 GtsWGNode
* gts_wgnode_new (GtsWGNodeClass
* klass
,
339 n
= GTS_WGNODE (gts_gnode_new (GTS_GNODE_CLASS (klass
)));
347 static void pnode_write (GtsGNode
* n
, FILE * fp
)
349 if (GTS_IS_NVERTEX (GTS_PNODE (n
)->data
))
350 fprintf (fp
, "label=\"%p:%s\",",
352 GTS_NVERTEX (GTS_PNODE (n
)->data
)->name
);
354 fprintf (fp
, "label=\"%p\",", GTS_PNODE (n
)->data
);
357 static void pnode_class_init (GtsPNodeClass
* klass
)
359 GTS_GNODE_CLASS (klass
)->write
= pnode_write
;
362 static void pnode_init (GtsPNode
* pn
)
370 * Returns: the #GtsPNodeClass.
372 GtsPNodeClass
* gts_pnode_class (void)
374 static GtsPNodeClass
* klass
= NULL
;
377 GtsObjectClassInfo pnode_info
= {
380 sizeof (GtsPNodeClass
),
381 (GtsObjectClassInitFunc
) pnode_class_init
,
382 (GtsObjectInitFunc
) pnode_init
,
383 (GtsArgSetFunc
) NULL
,
386 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
395 * @klass: a #GtsPNodeClass.
398 * Returns: a new #GtsPNode associated with @data.
400 GtsPNode
* gts_pnode_new (GtsPNodeClass
* klass
, gpointer data
)
404 pn
= GTS_PNODE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
412 static void fnode_write (GtsGNode
* n
, FILE * fp
)
414 fprintf (fp
, "label=\"%p\",", GTS_FNODE (n
)->f
);
417 static void fnode_class_init (GtsGNodeClass
* klass
)
419 klass
->write
= fnode_write
;
422 static void fnode_init (GtsFNode
* fn
)
430 * Returns: the #GtsFNodeClass.
432 GtsFNodeClass
* gts_fnode_class (void)
434 static GtsFNodeClass
* klass
= NULL
;
437 GtsObjectClassInfo fnode_info
= {
440 sizeof (GtsFNodeClass
),
441 (GtsObjectClassInitFunc
) fnode_class_init
,
442 (GtsObjectInitFunc
) fnode_init
,
443 (GtsArgSetFunc
) NULL
,
446 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_gnode_class ()),
455 * @klass: a #GtsFNodeClass.
458 * Returns: a new #GtsFNode associated with face @f.
460 GtsFNode
* gts_fnode_new (GtsFNodeClass
* klass
, GtsFace
* f
)
464 g_return_val_if_fail (f
!= NULL
, NULL
);
466 fn
= GTS_FNODE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
474 static void gedge_destroy (GtsObject
* object
)
476 GtsGEdge
* ge
= GTS_GEDGE (object
);
479 gts_container_remove (GTS_CONTAINER (ge
->n1
), GTS_CONTAINEE (ge
));
481 gts_container_remove (GTS_CONTAINER (ge
->n2
), GTS_CONTAINEE (ge
));
483 (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class
->destroy
) (object
);
486 static void gedge_remove_container (GtsContainee
* i
, GtsContainer
* c
)
488 GtsGEdge
* ge
= GTS_GEDGE (i
);
489 GtsGNode
* n1
= ge
->n1
;
490 GtsGNode
* n2
= ge
->n2
;
492 ge
->n1
= ge
->n2
= NULL
;
493 if (n1
!= NULL
&& n2
!= NULL
) {
494 if (GTS_CONTAINER (n1
) == c
) {
495 if (n2
&& n2
!= n1
) gts_container_remove (GTS_CONTAINER (n2
), i
);
497 else if (GTS_CONTAINER (n2
) == c
) {
498 if (n1
&& n1
!= n2
) gts_container_remove (GTS_CONTAINER (n1
), i
);
501 g_assert_not_reached ();
502 (* GTS_OBJECT_CLASS (gts_gedge_class ())->parent_class
->destroy
)
507 static gboolean
gedge_is_contained (GtsContainee
* i
, GtsContainer
* c
)
509 GtsGEdge
* ge
= GTS_GEDGE (i
);
511 if (GTS_CONTAINER (ge
->n1
) == c
|| GTS_CONTAINER (ge
->n2
) == c
)
516 static void gedge_class_init (GtsGEdgeClass
* klass
)
519 klass
->weight
= NULL
;
521 GTS_CONTAINEE_CLASS (klass
)->remove_container
= gedge_remove_container
;
522 GTS_CONTAINEE_CLASS (klass
)->is_contained
= gedge_is_contained
;
524 GTS_OBJECT_CLASS (klass
)->destroy
= gedge_destroy
;
527 static void gedge_init (GtsGEdge
* object
)
529 object
->n1
= object
->n2
= NULL
;
535 * Returns: the #GtsGEdgeClass.
537 GtsGEdgeClass
* gts_gedge_class (void)
539 static GtsGEdgeClass
* klass
= NULL
;
542 GtsObjectClassInfo gedge_info
= {
545 sizeof (GtsGEdgeClass
),
546 (GtsObjectClassInitFunc
) gedge_class_init
,
547 (GtsObjectInitFunc
) gedge_init
,
548 (GtsArgSetFunc
) NULL
,
551 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_containee_class ()),
560 * @klass: a #GtsGEdgeClass.
562 * @n2: another #GtsGNode.
564 * Returns: a new #GtsGEdge linking @n1 and @n2.
566 GtsGEdge
* gts_gedge_new (GtsGEdgeClass
* klass
, GtsGNode
* n1
, GtsGNode
* n2
)
570 g_return_val_if_fail (n1
!= NULL
, NULL
);
571 g_return_val_if_fail (n2
!= NULL
, NULL
);
573 object
= GTS_GEDGE (gts_object_new (GTS_OBJECT_CLASS (klass
)));
575 gts_container_add (GTS_CONTAINER (n1
), GTS_CONTAINEE (object
));
578 gts_container_add (GTS_CONTAINER (n2
), GTS_CONTAINEE (object
));
581 object
= (* klass
->link
) (object
, n1
, n2
);
590 * Returns: the weight of edge @e as defined by the weight() method of
593 gfloat
gts_gedge_weight (GtsGEdge
* e
)
595 g_return_val_if_fail (e
!= NULL
, 0.);
597 if (GTS_GEDGE_CLASS (GTS_OBJECT (e
)->klass
)->weight
)
598 return (* GTS_GEDGE_CLASS (GTS_OBJECT (e
)->klass
)->weight
) (e
);
604 static void pgedge_write (GtsGEdge
* ge
, FILE * fp
)
606 if (GTS_IS_EDGE (GTS_PGEDGE (ge
)->data
)) {
607 GtsEdge
* e
= GTS_PGEDGE (ge
)->data
;
608 guint n
= g_slist_length (e
->triangles
);
610 fprintf (fp
, "label=\"%p:%s:%d\",color=%s", e
,
611 GTS_IS_NEDGE (e
) ? GTS_NEDGE (e
)->name
: "",
621 fprintf (fp
, "label=\"%p\",", GTS_PGEDGE (ge
)->data
);
624 static void pgedge_class_init (GtsPGEdgeClass
* klass
)
626 GTS_GEDGE_CLASS (klass
)->write
= pgedge_write
;
629 static void pgedge_init (GtsPGEdge
* e
)
637 * Returns: the #GtsPGEdgeClass.
639 GtsPGEdgeClass
* gts_pgedge_class (void)
641 static GtsPGEdgeClass
* klass
= NULL
;
644 GtsObjectClassInfo pgedge_info
= {
647 sizeof (GtsPGEdgeClass
),
648 (GtsObjectClassInitFunc
) pgedge_class_init
,
649 (GtsObjectInitFunc
) pgedge_init
,
650 (GtsArgSetFunc
) NULL
,
653 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()),
662 * @klass: a #GtsPGEdgeClass.
664 * @n2: another #GtsGNode.
667 * Returns: a new #GtsPGEdge associated with @data linking @n1 and @n2.
669 GtsPGEdge
* gts_pgedge_new (GtsPGEdgeClass
* klass
,
676 we
= GTS_PGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass
), g1
, g2
));
684 static gfloat
wgedge_weight (GtsGEdge
* e
)
686 return GTS_WGEDGE (e
)->weight
;
689 static void wgedge_class_init (GtsWGEdgeClass
* klass
)
691 GTS_GEDGE_CLASS (klass
)->weight
= wgedge_weight
;
694 static void wgedge_init (GtsWGEdge
* e
)
702 * Returns: the #GtsWGEdgeClass.
704 GtsWGEdgeClass
* gts_wgedge_class (void)
706 static GtsWGEdgeClass
* klass
= NULL
;
709 GtsObjectClassInfo wgedge_info
= {
712 sizeof (GtsWGEdgeClass
),
713 (GtsObjectClassInitFunc
) wgedge_class_init
,
714 (GtsObjectInitFunc
) wgedge_init
,
715 (GtsArgSetFunc
) NULL
,
718 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_gedge_class ()),
727 * @klass: a #GtsWGEdgeClass.
729 * @n2: another #GtsGNode.
730 * @weight: the weight of the new edge.
732 * Returns: a new #GtsWGEdge of weight @weight linking @n1 and @n2.
734 GtsWGEdge
* gts_wgedge_new (GtsWGEdgeClass
* klass
,
741 we
= GTS_WGEDGE (gts_gedge_new (GTS_GEDGE_CLASS (klass
), g1
, g2
));
749 static void graph_init (GtsGraph
* g
)
751 g
->graph_class
= gts_graph_class ();
752 g
->node_class
= gts_gnode_class ();
753 g
->edge_class
= gts_gedge_class ();
756 static void graph_write (GtsObject
* object
, FILE * fp
)
758 GtsGraph
* graph
= GTS_GRAPH (object
);
760 fprintf (fp
, " %s %s %s",
761 object
->klass
->info
.name
,
762 GTS_OBJECT_CLASS (graph
->node_class
)->info
.name
,
763 GTS_OBJECT_CLASS (graph
->edge_class
)->info
.name
);
766 static void graph_read (GtsObject
** object
, GtsFile
* f
)
768 GtsObjectClass
* klass
;
770 if (f
->type
!= GTS_STRING
) {
771 gts_file_error (f
, "expecting a string (GtsGNodeClass)");
774 klass
= gts_object_class_from_name (f
->token
->str
);
776 gts_file_error (f
, "unknown class `%s'", f
->token
->str
);
779 if (!gts_object_class_is_from_class (klass
, gts_gnode_class ())) {
780 gts_file_error (f
, "class `%s' is not a GtsGNodeClass", f
->token
->str
);
783 GTS_GRAPH (*object
)->node_class
= GTS_GNODE_CLASS (klass
);
784 gts_file_next_token (f
);
786 if (f
->type
!= GTS_STRING
) {
787 gts_file_error (f
, "expecting a string (GtsGEdgeClass)");
790 klass
= gts_object_class_from_name (f
->token
->str
);
792 gts_file_error (f
, "unknown class `%s'", f
->token
->str
);
795 if (!gts_object_class_is_from_class (klass
, gts_gedge_class ())) {
796 gts_file_error (f
, "class `%s' is not a GtsGEdgeClass", f
->token
->str
);
799 GTS_GRAPH (*object
)->edge_class
= GTS_GEDGE_CLASS (klass
);
800 gts_file_next_token (f
);
803 static void graph_class_init (GtsGraphClass
* klass
)
805 klass
->weight
= NULL
;
807 GTS_OBJECT_CLASS (klass
)->write
= graph_write
;
808 GTS_OBJECT_CLASS (klass
)->read
= graph_read
;
814 * Returns: the #GtsGraphClass.
816 GtsGraphClass
* gts_graph_class (void)
818 static GtsGraphClass
* klass
= NULL
;
821 GtsObjectClassInfo graph_info
= {
824 sizeof (GtsGraphClass
),
825 (GtsObjectClassInitFunc
) graph_class_init
,
826 (GtsObjectInitFunc
) graph_init
,
827 (GtsArgSetFunc
) NULL
,
830 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_hash_container_class ()),
839 * @klass: a #GtsGraphClass.
840 * @node_class: a #GtsGNodeClass.
841 * @edge_class: a #GtsGEdgeClass.
843 * Returns: a new #GtsGraph using @node_class and @edge_class as node types.
845 GtsGraph
* gts_graph_new (GtsGraphClass
* klass
,
846 GtsGNodeClass
* node_class
,
847 GtsGEdgeClass
* edge_class
)
851 g_return_val_if_fail (klass
!= NULL
, NULL
);
852 g_return_val_if_fail (node_class
!= NULL
, NULL
);
853 g_return_val_if_fail (edge_class
!= NULL
, NULL
);
855 g
= GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass
)));
856 g
->node_class
= node_class
;
857 g
->edge_class
= edge_class
;
862 static void compute_degree (GtsGNode
* n
, gpointer
* data
)
864 GtsGraph
* g
= data
[0];
865 GtsRange
* degree
= data
[1];
867 gts_range_add_value (degree
, gts_gnode_degree (n
, g
));
871 * gts_graph_print_stats:
873 * @fp: a file pointer.
875 * Writes to @fp a summary of the properties of @g.
877 void gts_graph_print_stats (GtsGraph
* g
, FILE * fp
)
882 g_return_if_fail (g
!= NULL
);
883 g_return_if_fail (fp
!= NULL
);
885 fprintf (fp
, "# nodes: %d weight: %g\n",
886 gts_container_size (GTS_CONTAINER (g
)),
887 gts_graph_weight (g
));
888 fprintf (fp
, "# degree: ");
889 gts_range_init (°ree
);
892 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) compute_degree
, data
);
893 gts_range_update (°ree
);
894 gts_range_print (°ree
, fp
);
896 fprintf (fp
, "# edges cut: %d edges cut weight: %g\n",
897 gts_graph_edges_cut (g
),
898 gts_graph_edges_cut_weight (g
));
901 struct _GtsGraphTraverse
{
906 static void reset_level (GtsGNode
* n
)
912 * gts_graph_traverse_new:
914 * @n: a #GtsGNode belonging to @g.
915 * @type: the type of traversal.
916 * @reinit: if %TRUE, the traversal is reinitialized.
918 * Returns: a new #GtsGraphTraverse initialized for the traversal of
919 * @g of type @type, starting from @n.
921 GtsGraphTraverse
* gts_graph_traverse_new (GtsGraph
* g
,
923 GtsTraverseType type
,
926 GtsGraphTraverse
* t
;
928 g_return_val_if_fail (g
!= NULL
, NULL
);
929 g_return_val_if_fail (n
!= NULL
, NULL
);
930 g_return_val_if_fail (gts_containee_is_contained (GTS_CONTAINEE (n
),
935 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) reset_level
, NULL
);
937 t
= g_malloc (sizeof (GtsGraphTraverse
));
938 t
->q
= gts_fifo_new ();
941 gts_fifo_push (t
->q
, n
);
946 static void push_neighbor (GtsGNode
* n
, gpointer
* data
)
948 GtsFifo
* q
= data
[0];
949 GtsGNode
* u
= data
[1];
952 n
->level
= u
->level
+ 1;
953 gts_fifo_push (q
, n
);
958 * gts_graph_traverse_next:
959 * @t: a #GtsGraphTraverse.
961 * Returns: the next #GtsGNode of the traversal defined by @t or %NULL
962 * if the traversal is complete.
964 GtsGNode
* gts_graph_traverse_next (GtsGraphTraverse
* t
)
968 g_return_val_if_fail (t
!= NULL
, NULL
);
970 u
= gts_fifo_pop (t
->q
);
976 gts_gnode_foreach_neighbor (u
, t
->g
, (GtsFunc
) push_neighbor
, data
);
983 * gts_graph_traverse_what_next:
984 * @t: a #GtsGraphTraverse.
986 * Returns: the next #GtsGNode of the traversal defined by @t or %NULL
987 * if the traversal is complete but without advancing the traversal.
989 GtsGNode
* gts_graph_traverse_what_next (GtsGraphTraverse
* t
)
991 g_return_val_if_fail (t
!= NULL
, NULL
);
993 return gts_fifo_top (t
->q
);
997 * gts_graph_traverse_destroy:
998 * @t: a #GtsGraphTraverse.
1000 * Frees all the memory allocated for @t.
1002 void gts_graph_traverse_destroy (GtsGraphTraverse
* t
)
1004 g_return_if_fail (t
!= NULL
);
1006 gts_fifo_destroy (t
->q
);
1010 static void edge_foreach_node (GtsGNode
* n
, gpointer
* info
)
1012 GtsFunc func
= (GtsFunc
) info
[0];
1013 gpointer data
= info
[1];
1014 GHashTable
* hash
= info
[2];
1015 GSList
* i
= GTS_SLIST_CONTAINER (n
)->items
;
1018 GtsGEdge
* e
= i
->data
;
1019 if (!g_hash_table_lookup (hash
, e
)) {
1021 g_hash_table_insert (hash
, e
, e
);
1028 * gts_graph_foreach_edge:
1030 * @func: a #GtsFunc.
1031 * @data: user data to be passed to @func.
1033 * Calls @func for each #GtsEdge of @g.
1035 void gts_graph_foreach_edge (GtsGraph
* g
, GtsFunc func
, gpointer data
)
1040 g_return_if_fail (g
!= NULL
);
1041 g_return_if_fail (func
!= NULL
);
1045 info
[2] = hash
= g_hash_table_new (NULL
, NULL
);
1046 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) edge_foreach_node
, info
);
1047 g_hash_table_destroy (hash
);
1054 * Returns: the weight of graph @g as defined by the weight() method
1055 * of #GtsGraphClass.
1057 gfloat
gts_graph_weight (GtsGraph
* g
)
1059 g_return_val_if_fail (g
!= NULL
, 0.);
1061 if (GTS_GRAPH_CLASS (GTS_OBJECT (g
)->klass
)->weight
)
1062 return (* GTS_GRAPH_CLASS (GTS_OBJECT (g
)->klass
)->weight
) (g
);
1063 return (gfloat
) gts_container_size (GTS_CONTAINER (g
));
1067 * gts_graph_distance_sum:
1069 * @center: a #GtsGNode of @g.
1071 * Returns: the sum of the distances between all the other #GtsGNode
1072 * of @g and @center.
1074 guint
gts_graph_distance_sum (GtsGraph
* g
, GtsGNode
* center
)
1076 GtsGraphTraverse
* t
;
1080 g_return_val_if_fail (g
!= NULL
, 0);
1081 g_return_val_if_fail (center
!= NULL
, 0);
1083 t
= gts_graph_traverse_new (g
, center
, GTS_BREADTH_FIRST
, TRUE
);
1084 while ((n
= gts_graph_traverse_next (t
)))
1085 sum
+= n
->level
- 1;
1086 gts_graph_traverse_destroy (t
);
1092 * gts_graph_farthest:
1094 * @gnodes: a list of #GtsGNode belonging to @g.
1096 * Returns: the #GtsGNode belonging to @g and farthest from all the nodes in
1097 * @gnodes (hmmm, definition of "farthest"?).
1099 GtsGNode
* gts_graph_farthest (GtsGraph
* g
, GSList
* gnodes
)
1101 GtsGNode
* farthest
= NULL
;
1103 gboolean reinit
= TRUE
, changed
= TRUE
;
1106 g_return_val_if_fail (g
!= NULL
, NULL
);
1108 /* initialize traversals */
1111 GTS_OBJECT (i
->data
)->reserved
=
1112 gts_graph_traverse_new (g
, i
->data
, GTS_BREADTH_FIRST
, reinit
);
1121 GtsGraphTraverse
* t
= GTS_OBJECT (i
->data
)->reserved
;
1123 while ((n
= gts_graph_traverse_what_next (t
)) && n
->level
== level
) {
1126 gts_graph_traverse_next (t
);
1133 /* destroy traversals */
1136 gts_graph_traverse_destroy (GTS_OBJECT (i
->data
)->reserved
);
1137 GTS_OBJECT (i
->data
)->reserved
= NULL
;
1143 static void neighbor_count (GtsGNode
* n
, gpointer
* data
)
1145 guint
* cuts
= data
[0];
1146 GtsGraph
* g
= data
[1];
1148 if (!gts_containee_is_contained (GTS_CONTAINEE (n
), GTS_CONTAINER (g
)))
1152 static void count_edge_cuts (GtsGNode
* n
, gpointer
* data
)
1154 gts_gnode_foreach_neighbor (n
, NULL
, (GtsFunc
) neighbor_count
, data
);
1158 * gts_graph_edges_cut:
1161 * Returns: the number of edges of @g connecting nodes belonging to @g
1162 * to nodes not belonging to @g.
1164 guint
gts_graph_edges_cut (GtsGraph
* g
)
1169 g_return_val_if_fail (g
!= NULL
, 0);
1173 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) count_edge_cuts
, data
);
1178 static void sum_edge_cuts_weight (GtsGNode
* n
, gpointer
* data
)
1180 gfloat
* weight
= data
[0];
1181 GtsGraph
* g
= data
[1];
1182 GSList
* i
= GTS_SLIST_CONTAINER (n
)->items
;
1185 GtsGNode
* n1
= GTS_GNODE_NEIGHBOR (n
, i
->data
);
1186 if (!gts_containee_is_contained (GTS_CONTAINEE (n1
), GTS_CONTAINER (g
)))
1187 *weight
+= gts_gedge_weight (i
->data
);
1193 * gts_graph_edges_cut_weight:
1196 * Returns: the sum of the weights of the edges of @g connecting nodes
1197 * belonging to @g to nodes not belonging to @g.
1199 gfloat
gts_graph_edges_cut_weight (GtsGraph
* g
)
1204 g_return_val_if_fail (g
!= NULL
, 0);
1208 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) sum_edge_cuts_weight
,
1215 * gts_graph_read_jostle:
1219 * Adds to @g the nodes and edges defined in the file pointed to by
1220 * @fp. This file must use the Jostle "graph" ASCII format.
1221 * The nodes created are of type #GtsNGNode and their identities are the
1222 * line number at which they appear in @fp.
1224 * Returns: 0 if the lecture was successful, the line number at which
1225 * an error occured otherwise (in which case the @error field of @fp
1228 guint
gts_graph_read_jostle (GtsGraph
* g
, GtsFile
* fp
)
1233 g_return_val_if_fail (g
!= NULL
, 1);
1234 g_return_val_if_fail (fp
!= NULL
, 1);
1236 if (fp
->type
!= GTS_INT
) {
1237 gts_file_error (fp
, "expecting an integer (number of nodes)");
1240 nn
= atoi (fp
->token
->str
);
1241 gts_file_next_token (fp
);
1243 if (fp
->type
!= GTS_INT
) {
1244 gts_file_error (fp
, "expecting an integer (number of edges)");
1247 ne
= atoi (fp
->token
->str
);
1249 gts_file_first_token_after (fp
, '\n');
1250 nodes
= g_malloc (sizeof (GtsGNode
*)*(nn
+ 1));
1253 while (n
< nn
&& fp
->type
!= GTS_ERROR
) {
1254 GtsNGNode
* node
= gts_ngnode_new (gts_ngnode_class (), fp
->line
);
1256 nodes
[n
++] = GTS_GNODE (node
);
1257 gts_container_add (GTS_CONTAINER (g
), GTS_CONTAINEE (node
));
1259 if (fp
->type
!= GTS_INT
)
1260 gts_file_error (fp
, "expecting an integer (node index)");
1262 guint in
= atoi (fp
->token
->str
);
1264 if (in
== 0 || in
> nn
)
1265 gts_file_error (fp
, "node index `%d' is out of range `[1,%d]'",
1268 gts_file_error (fp
, "node index `%d' references itself", in
);
1270 gts_gedge_new (g
->edge_class
, GTS_GNODE (node
), nodes
[in
- 1]);
1272 gts_file_next_token (fp
);
1275 } while (fp
->type
!= GTS_ERROR
&& fp
->type
!= '\n');
1279 if (fp
->type
!= GTS_ERROR
) {
1281 gts_file_error (fp
, "only `%d' nodes read out of `%d'",
1284 gts_file_error (fp
, "`%d' unallocated edges remaining",
1288 if (fp
->type
== GTS_ERROR
)
1293 static void count_edges (GtsGEdge
* e
, guint
* nedge
)
1298 static void write_node (GtsObject
* node
, gpointer
* data
)
1300 FILE * fp
= data
[0];
1301 guint
* nnode
= data
[1];
1303 node
->reserved
= GUINT_TO_POINTER ((*nnode
)++);
1304 if (node
->klass
->write
)
1305 (* node
->klass
->write
) (node
, fp
);
1309 static void write_edge (GtsGEdge
* edge
, FILE * fp
)
1311 fprintf (fp
, "%u %u",
1312 GPOINTER_TO_UINT (GTS_OBJECT (edge
->n1
)->reserved
),
1313 GPOINTER_TO_UINT (GTS_OBJECT (edge
->n2
)->reserved
));
1314 if (GTS_OBJECT (edge
)->klass
->write
)
1315 (* GTS_OBJECT (edge
)->klass
->write
) (GTS_OBJECT (edge
), fp
);
1322 * @fp: a file pointer.
1324 * Writes in the file @fp an ASCII representation of @g. The file
1325 * format is as follows.
1327 * All the lines beginning with #GTS_COMMENTS are ignored. The first line
1328 * contains two unsigned integers separated by spaces. The first
1329 * integer is the number of nodes, nn, the second is the number of
1332 * Follows nn lines containing node description.
1333 * Follows ne lines containing the two indices (starting
1334 * from one) of the nodes of each edge.
1336 * The format described above is the least common denominator to all
1337 * GTS files. Consistent with an object-oriented approach, the GTS
1338 * file format is extensible. Each of the lines of the file can be
1339 * extended with user-specific attributes accessible through the
1340 * read() and write() virtual methods of each of the objects written
1341 * (graph, nodes or edges). When read with different object classes,
1342 * these extra attributes are just ignored.
1344 void gts_graph_write (GtsGraph
* g
, FILE * fp
)
1346 guint nnode
= 1, nedge
= 0;
1349 g_return_if_fail (g
!= NULL
);
1350 g_return_if_fail (fp
!= NULL
);
1352 gts_graph_foreach_edge (g
, (GtsFunc
) count_edges
, &nedge
);
1353 fprintf (fp
, "%u %u", gts_container_size (GTS_CONTAINER (g
)), nedge
);
1354 if (GTS_OBJECT (g
)->klass
->write
)
1355 (* GTS_OBJECT (g
)->klass
->write
) (GTS_OBJECT (g
), fp
);
1359 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) write_node
, data
);
1360 gts_graph_foreach_edge (g
, (GtsFunc
) write_edge
, fp
);
1361 gts_container_foreach (GTS_CONTAINER (g
),
1362 (GtsFunc
) gts_object_reset_reserved
, NULL
);
1369 * Reads a graph from a file.
1371 * Returns: the new #GtsGraph or %NULL if an error occured (in which
1372 * case the @error field of @fp is set).
1374 GtsGraph
* gts_graph_read (GtsFile
* fp
)
1380 g_return_val_if_fail (fp
!= NULL
, NULL
);
1382 if (fp
->type
!= GTS_INT
) {
1383 gts_file_error (fp
, "expecting an integer (number of nodes)");
1386 nn
= atoi (fp
->token
->str
);
1387 gts_file_next_token (fp
);
1389 if (fp
->type
!= GTS_INT
) {
1390 gts_file_error (fp
, "expecting an integer (number of edges)");
1393 ne
= atoi (fp
->token
->str
);
1395 gts_file_next_token (fp
);
1396 if (fp
->type
!= '\n') {
1397 GtsObjectClass
* klass
;
1403 if (fp
->type
!= GTS_STRING
) {
1404 gts_file_error (fp
, "expecting a string (GtsGraphClass)");
1407 klass
= gts_object_class_from_name (fp
->token
->str
);
1408 if (klass
== NULL
) {
1409 gts_file_error (fp
, "unknown class `%s'", fp
->token
->str
);
1412 if (!gts_object_class_is_from_class (klass
, gts_graph_class ())) {
1413 gts_file_error (fp
, "class `%s' is not a GtsGraphClass", fp
->token
->str
);
1416 g
= GTS_GRAPH (gts_object_new (klass
));
1417 g
->graph_class
= GTS_GRAPH_CLASS (klass
);
1418 gts_file_next_token (fp
);
1419 (* klass
->read
) ((GtsObject
**) &g
, fp
);
1420 if (fp
->type
== GTS_ERROR
) {
1421 gts_object_destroy (GTS_OBJECT (g
));
1426 g
= GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (gts_graph_class ())));
1427 gts_file_first_token_after (fp
, '\n');
1431 nodes
= g_malloc ((nn
+ 1)*sizeof (GtsGNode
*));
1434 while (n
< nn
&& fp
->type
!= GTS_ERROR
) {
1435 GtsObject
* new_node
=
1436 gts_object_new (GTS_OBJECT_CLASS (g
->node_class
));
1438 gts_container_add (GTS_CONTAINER (g
), GTS_CONTAINEE (new_node
));
1439 if (GTS_OBJECT_CLASS (g
->node_class
)->read
)
1440 (*GTS_OBJECT_CLASS (g
->node_class
)->read
) (&new_node
, fp
);
1441 gts_file_first_token_after (fp
, '\n');
1442 nodes
[n
++] = GTS_GNODE (new_node
);
1444 if (fp
->type
== GTS_ERROR
)
1448 while (n
< ne
&& fp
->type
!= GTS_ERROR
) {
1451 if (fp
->type
!= GTS_INT
)
1452 gts_file_error (fp
, "expecting an integer (first node index)");
1454 n1
= atoi (fp
->token
->str
);
1455 if (n1
== 0 || n1
> nn
)
1456 gts_file_error (fp
, "node index `%d' is out of range `[1,%d]'",
1459 gts_file_next_token (fp
);
1460 if (fp
->type
!= GTS_INT
)
1461 gts_file_error (fp
, "expecting an integer (second node index)");
1463 n2
= atoi (fp
->token
->str
);
1464 if (n2
== 0 || n2
> nn
)
1465 gts_file_error (fp
, "node index `%d' is out of range `[1,%d]'",
1468 GtsGEdge
* new_edge
=
1469 gts_gedge_new (g
->edge_class
, nodes
[n1
- 1], nodes
[n2
- 1]);
1471 gts_file_next_token (fp
);
1472 if (fp
->type
!= '\n')
1473 if (GTS_OBJECT_CLASS (g
->edge_class
)->read
)
1474 (*GTS_OBJECT_CLASS (g
->edge_class
)->read
)
1475 ((GtsObject
**) &new_edge
, fp
);
1476 gts_file_first_token_after (fp
, '\n');
1484 if (fp
->type
== GTS_ERROR
) {
1485 gts_allow_floating_gnodes
= TRUE
;
1487 gts_object_destroy (GTS_OBJECT (nodes
[nn
-- - 1]));
1488 gts_allow_floating_gnodes
= FALSE
;
1492 if (fp
->type
== GTS_ERROR
) {
1493 gts_object_destroy (GTS_OBJECT (g
));
1499 static void write_dot_node (GtsGNode
* node
, gpointer
* data
)
1501 FILE * fp
= data
[0];
1502 guint
* nnode
= data
[1];
1504 fprintf (fp
, " n%u", *nnode
);
1505 if (GTS_GNODE_CLASS (GTS_OBJECT (node
)->klass
)->write
) {
1507 (* GTS_GNODE_CLASS (GTS_OBJECT (node
)->klass
)->write
) (node
, fp
);
1511 GTS_OBJECT (node
)->reserved
= GUINT_TO_POINTER ((*nnode
)++);
1514 static void write_dot_edge (GtsGEdge
* edge
, FILE * fp
)
1516 fprintf (fp
, " n%u -> n%u",
1517 GPOINTER_TO_UINT (GTS_OBJECT (edge
->n1
)->reserved
),
1518 GPOINTER_TO_UINT (GTS_OBJECT (edge
->n2
)->reserved
));
1519 if (GTS_GEDGE_CLASS (GTS_OBJECT (edge
)->klass
)->write
) {
1521 (* GTS_GEDGE_CLASS (GTS_OBJECT (edge
)->klass
)->write
) (edge
, fp
);
1528 * gts_graph_write_dot:
1530 * @fp: a file pointer.
1532 * Writes in the file @fp an ASCII representation of @g in the dot format of
1535 void gts_graph_write_dot (GtsGraph
* g
, FILE * fp
)
1540 g_return_if_fail (g
!= NULL
);
1541 g_return_if_fail (fp
!= NULL
);
1543 fprintf (fp
, "digraph \"%p\" {\n", g
);
1546 gts_container_foreach (GTS_CONTAINER (g
), (GtsFunc
) write_dot_node
, data
);
1547 gts_graph_foreach_edge (g
, (GtsFunc
) write_dot_edge
, fp
);
1550 gts_container_foreach (GTS_CONTAINER (g
),
1551 (GtsFunc
) gts_object_reset_reserved
, NULL
);
1556 static gfloat
wgraph_weight (GtsGraph
* g
)
1558 return GTS_WGRAPH (g
)->weight
;
1561 static void wgraph_add (GtsContainer
* g
, GtsContainee
* n
)
1563 GtsWGraph
* wg
= GTS_WGRAPH (g
);
1564 gfloat w
= gts_gnode_weight (GTS_GNODE (n
));
1568 (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class
)->add
) (g
, n
);
1571 static void wgraph_remove (GtsContainer
* g
, GtsContainee
* n
)
1573 GTS_WGRAPH (g
)->weight
-= gts_gnode_weight (GTS_GNODE (n
));
1575 (* GTS_CONTAINER_CLASS (GTS_OBJECT_CLASS (gts_wgraph_class ())->parent_class
)->remove
) (g
, n
);
1578 static void wgraph_class_init (GtsWGraphClass
* klass
)
1580 GTS_GRAPH_CLASS (klass
)->weight
= wgraph_weight
;
1582 GTS_CONTAINER_CLASS (klass
)->add
= wgraph_add
;
1583 GTS_CONTAINER_CLASS (klass
)->remove
= wgraph_remove
;
1586 static void wgraph_init (GtsWGraph
* g
)
1594 * Returns: the #GtsWGraphClass.
1596 GtsWGraphClass
* gts_wgraph_class (void)
1598 static GtsWGraphClass
* klass
= NULL
;
1600 if (klass
== NULL
) {
1601 GtsObjectClassInfo wgraph_info
= {
1604 sizeof (GtsWGraphClass
),
1605 (GtsObjectClassInitFunc
) wgraph_class_init
,
1606 (GtsObjectInitFunc
) wgraph_init
,
1607 (GtsArgSetFunc
) NULL
,
1608 (GtsArgGetFunc
) NULL
1610 klass
= gts_object_class_new (GTS_OBJECT_CLASS (gts_graph_class ()),
1617 static void weight_max (GtsGNode
* n
, gfloat
* wmax
)
1619 gfloat w
= gts_gnode_weight (n
);
1626 * gts_wgraph_weight_max:
1627 * @wg: a #GtsWGraph.
1629 * Returns: the maximum weight of any vertices belonging to @g.
1631 gfloat
gts_wgraph_weight_max (GtsWGraph
* wg
)
1633 gfloat wmax
= - G_MAXFLOAT
;
1635 g_return_val_if_fail (wg
!= NULL
, 0.);
1637 gts_container_foreach (GTS_CONTAINER (wg
), (GtsFunc
) weight_max
, &wmax
);
1644 static void create_node (GtsFace
* f
, GtsGraph
* graph
)
1646 GtsFNode
* fn
= gts_fnode_new (gts_fnode_class (), f
);
1648 gts_container_add (GTS_CONTAINER (graph
), GTS_CONTAINEE (fn
));
1649 GTS_OBJECT (f
)->reserved
= fn
;
1652 static void create_edge (GtsEdge
* e
, GtsSurface
* s
)
1654 GSList
* i
= e
->triangles
;
1657 GtsFace
* f
= i
->data
;
1658 if (GTS_IS_FACE (f
) && gts_face_has_parent_surface (f
, s
)) {
1659 GSList
* j
= i
->next
;
1661 GtsFace
* f1
= j
->data
;
1662 if (GTS_IS_FACE (f1
) && gts_face_has_parent_surface (f1
, s
))
1663 gts_pgedge_new (gts_pgedge_class (),
1664 GTS_OBJECT (f
)->reserved
,
1665 GTS_OBJECT (f1
)->reserved
,
1675 * gts_surface_graph_new:
1676 * @klass: a #GtsGraphClass.
1677 * @s: a #GtsSurface.
1679 * Returns: a new #GtsGraph representing the connectivity of the faces
1680 * of @s. This graph uses #GtsFGNode as nodes which allows to store
1681 * the dependencies between nodes and faces of @s.
1683 GtsGraph
* gts_surface_graph_new (GtsGraphClass
* klass
,
1688 g_return_val_if_fail (klass
!= NULL
, NULL
);
1689 g_return_val_if_fail (s
!= NULL
, NULL
);
1691 graph
= GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass
)));
1692 gts_surface_foreach_face (s
, (GtsFunc
) create_node
, graph
);
1693 gts_surface_foreach_edge (s
, (GtsFunc
) create_edge
, s
);
1694 gts_surface_foreach_face (s
, (GtsFunc
) gts_object_reset_reserved
, NULL
);
1699 static void create_segment_edge (GtsSegment
* s
, GtsGraph
* graph
)
1701 GtsGNode
* n1
= GTS_OBJECT (s
->v1
)->reserved
, * n2
;
1704 n1
= GTS_GNODE (gts_pnode_new (gts_pnode_class (), s
->v1
));
1705 gts_container_add (GTS_CONTAINER (graph
), GTS_CONTAINEE (n1
));
1706 GTS_OBJECT (s
->v1
)->reserved
= n1
;
1709 n2
= GTS_OBJECT (s
->v2
)->reserved
;
1711 n2
= GTS_GNODE (gts_pnode_new (gts_pnode_class (), s
->v2
));
1712 gts_container_add (GTS_CONTAINER (graph
), GTS_CONTAINEE (n2
));
1713 GTS_OBJECT (s
->v2
)->reserved
= n2
;
1716 gts_pgedge_new (gts_pgedge_class (), n1
, n2
, s
);
1719 static void reset_reserved (GtsSegment
* s
)
1721 GTS_OBJECT (s
->v1
)->reserved
= GTS_OBJECT (s
->v2
)->reserved
= NULL
;
1725 * gts_segments_graph_new:
1726 * @klass: a #GtsGraphClass.
1727 * @segments: a list of #GtsSegment.
1729 * Returns: a new #GtsGraph representing the connectivity of the segments
1732 GtsGraph
* gts_segments_graph_new (GtsGraphClass
* klass
,
1737 g_return_val_if_fail (klass
!= NULL
, NULL
);
1739 graph
= GTS_GRAPH (gts_object_new (GTS_OBJECT_CLASS (klass
)));
1740 g_slist_foreach (segments
, (GFunc
) create_segment_edge
, graph
);
1741 g_slist_foreach (segments
, (GFunc
) reset_reserved
, NULL
);
1746 static void add_to_surface (GtsGNode
* n
, GtsSurface
* s
)
1748 if (GTS_IS_FNODE (n
))
1749 gts_surface_add_face (s
, GTS_FNODE (n
)->f
);
1753 * gts_surface_graph_surface:
1754 * @surface_graph: a #GtsGraph using #GtsFGNode as nodes.
1755 * @s: a #GtsSurface.
1757 * Returns: a new #GtsSurface using the same classes as @s and
1758 * composed of the faces defined by @surface_graph.
1760 GtsSurface
* gts_surface_graph_surface (GtsGraph
* surface_graph
,
1765 g_return_val_if_fail (surface_graph
!= NULL
, NULL
);
1766 g_return_val_if_fail (s
!= NULL
, NULL
);
1768 s1
= gts_surface_new (GTS_SURFACE_CLASS (GTS_OBJECT (s
)->klass
),
1772 gts_container_foreach (GTS_CONTAINER (surface_graph
),
1773 (GtsFunc
) add_to_surface
, s1
);