summaryrefslogtreecommitdiff
path: root/src/gtkext/graph/cluster.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2019-03-15 10:55:03 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2019-03-15 10:55:03 (GMT)
commitf65f83fd222d14934b527152899359327813128e (patch)
tree742e0f08a82ba941e386e5e3764a84b13e0c9ffe /src/gtkext/graph/cluster.c
parent0a190905f31d7c395e1b26efe3abe443687429e5 (diff)
Tracked vertical links beyond their cluster.
Diffstat (limited to 'src/gtkext/graph/cluster.c')
-rw-r--r--src/gtkext/graph/cluster.c811
1 files changed, 563 insertions, 248 deletions
diff --git a/src/gtkext/graph/cluster.c b/src/gtkext/graph/cluster.c
index e425d67..444bd22 100644
--- a/src/gtkext/graph/cluster.c
+++ b/src/gtkext/graph/cluster.c
@@ -309,7 +309,7 @@ GGraphCluster *g_graph_cluster_new(GCodeBlock *block, segcnt_list *highlighted,
/******************************************************************************
* *
-* Paramètres : cluster = graphique de blocs à compléter. *
+* Paramètres : cluster = graphique de blocs à traiter. *
* *
* Description : Assigne à un bloc et son ensemble un emplacement initial. *
* *
@@ -762,36 +762,25 @@ void g_graph_cluster_setup_links(GGraphCluster *cluster)
/******************************************************************************
* *
* Paramètres : cluster = graphique de blocs à manipuler. *
+* idx = indice du lien éventuellement identifié. [OUT] *
* *
-* Description : Organise la disposition d'un ensemble de blocs basiques. *
+* Description : Détermine un éventuel lien entrant réellement vertical. *
* *
-* Retour : - *
+* Retour : Lien entrant véritablement vertical. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
+incoming_link_t *g_graph_cluster_find_real_straight_incoming(GGraphCluster *cluster, size_t *idx)
{
- size_t i; /* Boucle de parcours #1 */
+ incoming_link_t *result; /* Lien entrant à retourner */
size_t straight_idx; /* Lien vertical le plus adapté*/
size_t forced_idx; /* Lien vertical forcé */
bool drop_forced; /* Invalidation de cet indice */
+ size_t i; /* Boucle de parcours #1 */
leaving_link_t *leaving; /* Départ de lien */
GCodeBlock *block[2]; /* Accès rapide aux blocs */
- gint start; /* Position initiale de départ */
- gint end; /* Position initiale d'arrivée */
- leaving_link_t *straight_leaving; /* Lien à présenter vertical */
- size_t straight_index; /* Indice du lien vertical */
- gint straight_start; /* Position initiale de départ */
- size_t straight_level; /* Rang atteint en ligne droite*/
- const graph_rank_t *rank; /* Accès confortable au rang */
- size_t j; /* Boucle de parcours #2 */
- GGraphCluster *target; /* Unique sous-bloc visé */
-
- /**
- * Traitement amont : alignement sur une éventuelle origine.
- */
straight_idx = cluster->ta_count;
forced_idx = cluster->ta_count;
@@ -837,30 +826,69 @@ void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
}
- /* Recalage en fonction d'une éventuelle conduite forcée */
+ /* Détermination du résultat final */
if (drop_forced)
forced_idx = cluster->ta_count;
if (straight_idx < cluster->ta_count || forced_idx < cluster->ta_count)
{
- if (forced_idx < cluster->ta_count)
- {
- leaving = cluster->top_anchors[forced_idx]->other;
+ *idx = (forced_idx < cluster->ta_count ? forced_idx : straight_idx);
- end = g_graph_cluster_compute_incoming_link_position(cluster, forced_idx);
+ result = cluster->top_anchors[*idx];
- }
- else
- {
- leaving = cluster->top_anchors[straight_idx]->other;
+ }
- end = g_graph_cluster_compute_incoming_link_position(cluster, straight_idx);
+ else
+ result = NULL;
- }
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à manipuler. *
+* *
+* Description : Organise la disposition d'un ensemble de blocs basiques. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
+{
+ size_t idx; /* Indice de lien d'arrivée */
+ incoming_link_t *incoming; /* Arrivée de lien */
+ leaving_link_t *leaving; /* Départ de lien */
+ gint start; /* Position initiale de départ */
+ gint end; /* Position initiale d'arrivée */
+ size_t i; /* Boucle de parcours #1 */
+ leaving_link_t *straight_leaving; /* Lien à présenter vertical */
+ size_t straight_index; /* Indice du lien vertical */
+ gint straight_start; /* Position initiale de départ */
+ size_t straight_level; /* Rang atteint en ligne droite*/
+ const graph_rank_t *rank; /* Accès confortable au rang */
+ size_t j; /* Boucle de parcours #2 */
+ GGraphCluster *target; /* Unique sous-bloc visé */
+
+ /**
+ * Traitement amont : alignement sur une éventuelle origine.
+ */
+
+ incoming = g_graph_cluster_find_real_straight_incoming(cluster, &idx);
+
+ if (incoming != NULL)
+ {
+ leaving = incoming->other;
start = g_graph_cluster_compute_leaving_link_position(leaving->owner, leaving->index);
+ end = g_graph_cluster_compute_incoming_link_position(cluster, idx);
+
g_graph_cluster_offset_x(cluster, start - end);
}
@@ -897,15 +925,13 @@ void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
{
if (get_graph_rank(rank) < straight_level)
{
- start = straight_start;
-
/* Répartition à gauche du lien */
for (j = rank->count; j > 0; j--)
if (*rank->clusters[j - 1]->parent_index < straight_index)
break;
- start -= LINK_MARGIN;
+ start = straight_start - LINK_MARGIN;
_place_graph_rank_clusters(rank->clusters, j, start, -1);
@@ -915,7 +941,7 @@ void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
if (*rank->clusters[j]->parent_index > straight_index)
break;
- start += 2 * LINK_MARGIN;
+ start = straight_start + LINK_MARGIN + cluster->right_offset;
_place_graph_rank_clusters(rank->clusters + j, rank->count - j, start, 1);
@@ -974,11 +1000,12 @@ void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
/******************************************************************************
* *
-* Paramètres : cluster = graphique de blocs à analyser. *
-* root = élément à ne jamais croiser dans la paternité. *
-* dir = préférence à actualiser si possible. [OUT] *
+* Paramètres : cluster = graphique de blocs à consulter. *
+* root = ensemble dont s'extraire. *
+* max = ordonnée maximale de la zone de travail. *
+* pos = abscisses minimale et maximale en bout. [OUT] *
* *
-* Description : Détermine une direction préférée pour la suite du bloc. *
+* Description : Calcule les abscisses extrèmes atteintes via liens de sortie.*
* *
* Retour : false si une incapacité de détermination a été rencontrée. *
* *
@@ -986,46 +1013,421 @@ void g_graph_cluster_dispatch_x(GGraphCluster *cluster)
* *
******************************************************************************/
-bool g_graph_cluster_get_exit_direction(const GGraphCluster *cluster, const GGraphCluster *root, LeavingLinkDir *dir)
+bool g_graph_cluster_compute_min_max_x_exit(const GGraphCluster *cluster, const GGraphCluster *root, gint pos[2])
{
bool result; /* Bilan à renvoyer */
size_t i; /* Boucle de parcours #1 */
const leaving_link_t *leaving; /* Lien sortant à traiter */
+ bool stop; /* Prépare la fin de parcours */
GGraphCluster *iter; /* Boucle de parcours #2 */
- LeavingLinkDir pref; /* Préférence du lien courant */
+ gint x; /* Abscisse rencontrée */
- result = true;
+ result = false;
- for (i = 0; i < cluster->ba_count && result; i++)
+ for (i = 0; i < cluster->ba_count; i++)
{
leaving = cluster->bottom_anchors[i];
- if (!leaving->cluster_exit)
+ if (leaving->other->type == ILT_LOOP)
continue;
+ stop = leaving->cluster_exit;
+
/* Validation d'une sortie du cluster d'origine */
- for (iter = leaving->other->owner; iter != NULL; iter = iter->owner)
- if (iter == root)
- break;
+ if (stop)
+ {
+ for (iter = leaving->other->owner; iter != NULL; iter = iter->owner)
+ if (iter == root)
+ break;
- if (iter != NULL)
- continue;
+ stop = (iter == NULL);
+
+ }
+
+ /* Poursuite du lien */
+
+ if (stop)
+ {
+ x = compute_leaving_link_position(leaving);
+
+ if (x < pos[0])
+ {
+ pos[0] = x;
+ result = true;
+ }
+
+ if (x > pos[1])
+ {
+ pos[1] = x;
+ result = true;
+ }
+
+ }
+
+ else
+ result |= g_graph_cluster_compute_min_max_x_exit(leaving->other->owner, root, pos);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à consulter. *
+* max = profondeur maximale des traitements en ordonnée. *
+* pos = ordonnées minimale et maximale en bout. [OUT] *
+* *
+* Description : Calcule les abscisses extrèmes atteintes horizontalement. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_graph_cluster_compute_min_max_horizontal(const GGraphCluster *cluster, gint max, gint pos[2])
+{
+ size_t i; /* Boucle de parcours */
+ const leaving_link_t *leaving; /* Lien sortant du bloc */
+
+ if (cluster->alloc.y < max)
+ {
+ if (cluster->alloc.x < pos[0])
+ pos[0] = cluster->alloc.x;
+
+ if ((cluster->alloc.x + cluster->alloc.width) > pos[1])
+ pos[1] = cluster->alloc.x + cluster->alloc.width;
+
+ for (i = 0; i < cluster->ba_count; i++)
+ {
+ leaving = cluster->bottom_anchors[i];
+
+ if (leaving->other->type == ILT_LOOP)
+ continue;
+
+ g_graph_cluster_compute_min_max_horizontal(leaving->other->owner, max, pos);
+
+ }
+
+ }
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à manipuler. *
+* *
+* Description : Définit d'éventuels décalages pour les lignes verticales. *
+* *
+* Retour : true si un changement est survenu, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_graph_cluster_dispatch_define_extra_offset(GGraphCluster *cluster)
+{
+ bool result; /* Evolution à retourner */
+ size_t i; /* Boucle de parcours #1 */
+ leaving_link_t *straight_leaving; /* Lien à présenter vertical */
+ size_t straight_index; /* Indice du lien vertical */
+ gint straight_start; /* Position initiale de départ */
+ size_t straight_level; /* Rang atteint en ligne droite*/
+ const graph_rank_t *rank; /* Accès confortable au rang */
+ size_t j; /* Boucle de parcours #2 */
+ gint straight_depth; /* Profondeur du lien vertical */
+ gint depth; /* Profondeur du lien voisin */
+ gint x_exit[2]; /* Bornes des liens de sortie */
+#ifndef NDEBUG
+ bool status; /* Validation des obtentions */
+#endif
+ gint x_used[2]; /* Bornes d'utilisations */
+ bool changed; /* Note un changement d'état */
+ gint offset; /* Décalage à appliquer */
+ GGraphCluster *parent; /* Racine pour les mises à jour*/
+ GGraphCluster *target; /* Unique sous-bloc visé */
+ leaving_link_t *leaving; /* Départ de lien */
+
+ result = false;
+
+ /**
+ * Le corps de cette fonction est calqué sur celui de g_graph_cluster_dispatch_x(),
+ * à partir du traitement amon.
+ *
+ * Toute modification dans ces parties doit donc être synchronisée.
+ */
+
+ /* Recherche d'une limite verticale */
+
+ straight_leaving = NULL;
+
+ for (i = 0; i < cluster->ba_count; i++)
+ if (SHOULD_BE_VERTICAL(cluster->bottom_anchors[i]))
+ {
+ straight_leaving = cluster->bottom_anchors[i];
+ straight_index = i;
+
+ straight_start = g_graph_cluster_compute_leaving_link_position(cluster, i);
+ straight_level = straight_leaving->straight_level;
+
+ break;
+
+ }
+
+ /* Il est désormais temps de placer tous les blocs de code inférieurs. */
+
+ for (i = 0; i < cluster->ranks_count; i++)
+ {
+ rank = &cluster->ranks[i];
+
+ /* Répartition autour d'une ligne verticale */
+ if (straight_leaving != NULL)
+ {
+ if (get_graph_rank(rank) < straight_level)
+ {
+ /* Répartition à gauche du lien */
+
+ for (j = rank->count; j > 0; j--)
+ if (*rank->clusters[j - 1]->parent_index < straight_index)
+ break;
+
+ /* Répartition à droite du lien */
+
+ for (j = 0; j < rank->count; j++)
+ if (*rank->clusters[j]->parent_index > straight_index)
+ break;
+
+ if (j < rank->count)
+ {
+ if (straight_leaving->cluster_exit)
+ {
+ straight_depth = straight_leaving->other->owner->alloc.y;
+
+ depth = G_MAXINT;
+
+ if (g_graph_cluster_compute_min_y_target(rank->clusters[j], cluster, &depth))
+ {
+ x_exit[0] = G_MAXINT;
+ x_exit[1] = G_MININT;
+
+#ifndef NDEBUG
+ status = g_graph_cluster_compute_min_max_x_exit(rank->clusters[j], cluster, x_exit);
+ assert(status);
+#else
+ g_graph_cluster_compute_min_max_x_exit(rank->clusters[j], cluster, x_exit);
+#endif
+
+ x_used[0] = G_MAXINT;
+ x_used[1] = G_MININT;
+
+ changed = false;
+
+ if (straight_depth > depth)
+ {
+ g_graph_cluster_compute_min_max_horizontal(rank->clusters[j],
+ straight_depth, x_used);
+
+ if (straight_start > x_used[0])
+ {
+ offset = straight_start - x_used[0] + LINK_MARGIN;
+
+ if (offset != 0)
+ {
+ cluster->right_offset += offset;
+ changed = true;
+ }
+
+ }
+
+ }
+
+ else
+ {
+ g_graph_cluster_compute_min_max_horizontal(straight_leaving->other->owner,
+ depth, x_used);
+
+ if (x_used[1] > x_exit[0])
+ {
+ offset = x_used[1] - x_exit[0] + LINK_MARGIN;
+
+ if (offset != 0)
+ {
+ cluster->right_offset += offset;
+ changed = true;
+ }
+
+ }
+
+ }
+
+ /* Réorganisation suite à changement ? */
+ if (changed)
+ {
+ result = true;
+
+ parent = cluster->owner;
+
+ if (parent != NULL)
+ {
+ g_graph_cluster_sort_leaving_links(parent);
+
+ for (i = 0; i < parent->ranks_count; i++)
+ reset_graph_rank_allocation(&parent->ranks[i]);
+
+ g_graph_cluster_dispatch_x(parent);
+
+ g_graph_cluster_set_y(parent, parent->alloc.y);
+
+ g_graph_cluster_sort_leaving_links(parent);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ result |= visit_and_accumulate_graph_rank(rank, g_graph_cluster_dispatch_define_extra_offset);
+
+ }
+
+ else if (get_graph_rank(rank) == straight_level)
+ {
+ result |= visit_and_accumulate_graph_rank(rank, g_graph_cluster_dispatch_define_extra_offset);
+
+ straight_leaving = NULL;
+
+ goto look_for_forced;
+
+ }
+
+ else
+ assert(false);
+
+ }
+
+ /* Répartition homogène */
+ else
+ {
+ result |= visit_and_accumulate_graph_rank(rank, g_graph_cluster_dispatch_define_extra_offset);
+
+ look_for_forced:
+
+ /* Lien vertical interne ? */
- pref = get_leaving_link_direction(leaving);
+ if (rank->count != 1)
+ continue;
+
+ target = rank->clusters[0];
+
+ if (target->ba_count != 1)
+ continue;
+
+ leaving = target->bottom_anchors[0];
+
+ if (leaving->forced_straight)
+ {
+ straight_leaving = leaving;
+ straight_index = 0;
+
+ straight_start = g_graph_cluster_compute_leaving_link_position(target, 0);
+ straight_level = leaving->straight_level;
- /* Si la direction est claire... */
- if (*dir == LLD_NO_PREF)
- *dir = pref;
+ }
- /* Multiples directions, on ne sait pas trancher ! */
- else if (*dir != pref)
- result = false;
+ }
}
- for (i = 0; i < cluster->ranks_count && result; i++)
- result = get_graph_rank_exit_direction(&cluster->ranks[i], root, dir);
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : cluster = graphique de blocs à analyser. *
+* x1 = abscisse de départ du lien d'origine. *
+* max = ordonnée la plus profonde à ne pas dépasser. *
+* *
+* Description : Détermine une direction préférée pour la suite du bloc. *
+* *
+* Retour : false si une incapacité de détermination a été rencontrée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+LeavingLinkDir g_graph_cluster_get_link_direction(const GGraphCluster *cluster, gint x1, gint max)
+{
+ LeavingLinkDir result; /* Préférence à retourner */
+ size_t left_points; /* Nombre de voix à gauche */
+ size_t left_straight; /* Nombre de voix à gauche bis */
+ size_t right_points; /* Nombre de voix à droite */
+ size_t right_straight; /* Nombre de voix à droite bis */
+ size_t i; /* Boucle de parcours #1 */
+ const leaving_link_t *leaving; /* Lien sortant à traiter */
+ LeavingLinkDir pref; /* Préférence du lien courant */
+
+ /* Analyse des différents liens */
+
+ left_points = 0;
+ left_straight = 0;
+ right_points = 0;
+ right_straight = 0;
+
+ for (i = 0; i < cluster->ba_count; i++)
+ {
+ leaving = cluster->bottom_anchors[i];
+
+ if (leaving->other->type == ILT_LOOP)
+ continue;
+
+ pref = get_leaving_link_direction(leaving, x1, max);
+
+ if (pref == LLD_TO_LEFT)
+ {
+ left_points++;
+ if (SHOULD_BE_VERTICAL(leaving))
+ left_straight++;
+ }
+ else
+ {
+ right_points++;
+ if (SHOULD_BE_VERTICAL(leaving))
+ right_straight++;
+ }
+
+ }
+
+ /* Décompte des points et élection du gagnant ! */
+
+ if (left_points > right_points)
+ result = LLD_TO_LEFT;
+
+ else if (left_points < right_points)
+ result = LLD_TO_RIGHT;
+
+ else
+ {
+ if (left_straight > right_straight)
+ result = LLD_TO_LEFT;
+
+ else if (left_straight < right_straight)
+ result = LLD_TO_RIGHT;
+
+ else
+ result = LLD_NO_PREF;
+
+ }
return result;
@@ -1046,6 +1448,10 @@ bool g_graph_cluster_get_exit_direction(const GGraphCluster *cluster, const GGra
void g_graph_cluster_sort_leaving_links(GGraphCluster *cluster)
{
+ gint max; /* Borne pour la profondeur */
+ size_t lr_sep; /* Séparation gauche / droite */
+ leaving_link_t *leaving; /* Lien sortant à traiter */
+ incoming_link_t *straight; /* Lien entrant vertical ? */
size_t i; /* Boucle de parcours */
leaving_link_t **left; /* Liens à placer à gauche */
leaving_link_t **center; /* Liens à placer au milieu */
@@ -1053,21 +1459,53 @@ void g_graph_cluster_sort_leaving_links(GGraphCluster *cluster)
size_t left_count; /* Quantité de liens à gauche */
size_t center_count; /* Quantité de liens au milieu */
size_t right_count; /* Quantité de liens à droite */
- leaving_link_t *leaving; /* Lien sortant à traiter */
LeavingLinkDir pref; /* Préférence du lien courant */
+ gint x1; /* Abscisse de départ de lien */
/**
- * On n'intervient que s'il y a lieu de le faire, notamment si les sorties
- * du groupe de blocs ont une direction claire.
+ * On n'intervient que s'il y a lieu de le faire...
*/
- pref = LLD_NO_PREF;
-
- if (!g_graph_cluster_get_exit_direction(cluster, cluster, &pref))
+ if (cluster->ba_count < 2)
goto done;
- if (cluster->ba_count < 2 || pref == LLD_NO_PREF)
- goto done;
+ /**
+ * Détermination de la profondeur maximale, à partir des liens verticaux.
+ *
+ * Ces liens seront centraux, donc inutile de déterminer la direction
+ * des autres liens passée une certaine profondeur verticale.
+ */
+
+ max = 0;
+ lr_sep = cluster->ba_count;
+
+ for (i = 0; i < cluster->ba_count; i++)
+ {
+ leaving = cluster->bottom_anchors[i];
+
+ straight = g_graph_cluster_find_real_straight_incoming(leaving->other->owner, (size_t []){ 0 });
+
+ if (straight == leaving->other)
+ {
+ /**
+ * Il ne peut y avoir à priori qu'un seul lien vertical au départ
+ * d'un bloc donné.
+ */
+ assert(max == 0);
+
+ max = leaving->other->owner->alloc.y;
+ lr_sep = i;
+
+ }
+
+ }
+
+ if (max == 0)
+ max = G_MAXINT;
+
+ /**
+ * Phase de réorganisation effective.
+ */
left = NULL;
center = NULL;
@@ -1083,21 +1521,15 @@ void g_graph_cluster_sort_leaving_links(GGraphCluster *cluster)
{
leaving = cluster->bottom_anchors[i];
- if (SHOULD_BE_VERTICAL(leaving))
- {
- if (leaving->cluster_exit)
- pref = get_leaving_link_direction(leaving);
- else
- pref = LLD_NO_PREF;
+ if (i == lr_sep)
+ pref = LLD_NO_PREF;
- }
else
{
- pref = LLD_NO_PREF;
+ x1 = compute_leaving_link_position(leaving);
- if (!g_graph_cluster_get_exit_direction(leaving->other->owner, leaving->other->owner, &pref))
- pref = LLD_NO_PREF;
+ pref = get_leaving_link_direction(leaving, x1, max);
}
@@ -1132,7 +1564,7 @@ void g_graph_cluster_sort_leaving_links(GGraphCluster *cluster)
{
qsort_r(left, left_count, sizeof(leaving_link_t *),
(__compar_d_fn_t)cmp_leaving_links,
- (LeavingLinkDir []) { LLD_TO_LEFT });
+ (leaving_cmp_info_t []) { { .root = cluster, .dir = LLD_TO_LEFT } });
for (i = 0; i < left_count; i++)
cluster->bottom_anchors[cluster->ba_count++] = left[i];
@@ -1154,7 +1586,7 @@ void g_graph_cluster_sort_leaving_links(GGraphCluster *cluster)
{
qsort_r(right, right_count, sizeof(leaving_link_t *),
(__compar_d_fn_t)cmp_leaving_links,
- (LeavingLinkDir []) { LLD_TO_RIGHT });
+ (leaving_cmp_info_t []) { { .root = cluster, .dir = LLD_TO_RIGHT } });
for (i = 0; i < right_count; i++)
cluster->bottom_anchors[cluster->ba_count++] = right[i];
@@ -1194,21 +1626,24 @@ void g_graph_cluster_sort_leaving_links(GGraphCluster *cluster)
/******************************************************************************
* *
* Paramètres : cluster = graphique de blocs à consulter. *
-* pos = ordonnées minimale et maximale en bout. [OUT] *
+* root = ensemble dont s'extraire. *
+* pos = ordonnée minimale en bout. [OUT] *
* *
* Description : Calcule les ordonnées extrèmes atteintes via liens sortants. *
* *
-* Retour : true si un lien sortant a été trouvé, false sinon. *
+* Retour : false si une incapacité de détermination a été rencontrée. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_graph_cluster_compute_min_max_bottom(const GGraphCluster *cluster, gint pos[2])
+bool g_graph_cluster_compute_min_y_target(const GGraphCluster *cluster, const GGraphCluster *root, gint *pos)
{
- bool result; /* Bilan à retourner */
- size_t i; /* Boucle de parcours */
+ bool result; /* Bilan à renvoyer */
+ size_t i; /* Boucle de parcours #1 */
const leaving_link_t *leaving; /* Lien sortant à traiter */
+ bool stop; /* Prépare la fin de parcours */
+ GGraphCluster *iter; /* Boucle de parcours #2 */
gint y; /* Ordonnée rencontrée */
result = false;
@@ -1217,23 +1652,41 @@ bool g_graph_cluster_compute_min_max_bottom(const GGraphCluster *cluster, gint p
{
leaving = cluster->bottom_anchors[i];
- if (!leaving->cluster_exit)
+ if (leaving->other->type == ILT_LOOP)
continue;
- result = true;
+ stop = leaving->cluster_exit;
- y = leaving->other->owner->alloc.y;
+ /* Validation d'une sortie du cluster d'origine */
- if (y < pos[0])
- pos[0] = y;
+ if (stop)
+ {
+ for (iter = leaving->other->owner; iter != NULL; iter = iter->owner)
+ if (iter == root)
+ break;
- if (pos[1] < y)
- pos[1] = y;
+ stop = (iter == NULL);
- }
+ }
- for (i = 0; i < cluster->ranks_count; i++)
- result |= compute_graph_rank_min_max_bottom(&cluster->ranks[i], pos);
+ /* Poursuite du lien ? */
+
+ if (stop)
+ {
+ y = leaving->other->owner->alloc.y;
+
+ if (y < *pos)
+ {
+ *pos = y;
+ result = true;
+ }
+
+ }
+
+ else
+ result |= g_graph_cluster_compute_min_y_target(leaving->other->owner, root, pos);
+
+ }
return result;
@@ -1318,148 +1771,6 @@ int g_graph_cluster_compare_by_origin(const GGraphCluster **cluster, const GGrap
/******************************************************************************
* *
-* Paramètres : cluster = graphique de blocs à consulter. *
-* stop = chef de file marquant l'arrêt des consultations. *
-* pos = ordonnées minimale et maximale en bout. [OUT] *
-* *
-* Description : Calcule les abscisses extrèmes atteintes horizontalement. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_graph_cluster_compute_min_max_horizontal(const GGraphCluster *cluster, const GGraphCluster *stop, gint pos[2])
-{
- size_t i; /* Boucle de parcours */
- const leaving_link_t *leaving; /* Lien sortant du bloc */
-
- if (cluster->alloc.y < stop->alloc.y)
- {
- if (cluster->alloc.x < pos[0])
- pos[0] = cluster->alloc.x;
-
- if ((cluster->alloc.x + cluster->alloc.width) > pos[1])
- pos[1] = cluster->alloc.x + cluster->alloc.width;
-
- for (i = 0; i < cluster->ba_count; i++)
- {
- leaving = cluster->bottom_anchors[i];
-
- if (leaving->other->type == ILT_LOOP)
- continue;
-
- g_graph_cluster_compute_min_max_horizontal(leaving->other->owner, stop, pos);
-
- }
-
- }
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : cluster = graphique de blocs à manipuler. *
-* *
-* Description : S'assure que les liens verticaux ne traversent pas de bloc. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_graph_cluster_ensure_space_for_straight(GGraphCluster *cluster)
-{
- size_t i; /* Boucle de parcours */
- size_t first; /* Premier lien vertical */
- size_t last; /* Dernier lien vertical */
- size_t straight_level; /* Rang atteint en ligne droite*/
- GGraphCluster *stop; /* Borne d'arrêt correspondante*/
- const leaving_link_t *leaving; /* Lien sortant du bloc */
- gint pos[2]; /* Bornes horizontales */
- gint max; /* Borne horizontale */
-
- for (i = 0; i < cluster->ranks_count; i++)
- visit_graph_rank(&cluster->ranks[i], g_graph_cluster_ensure_space_for_straight);
-
- first = cluster->ba_count;
- last = 0;
-
- straight_level = 0;
- stop = NULL;
-
- for (i = 0; i < cluster->ba_count; i++)
- {
- leaving = cluster->bottom_anchors[i];
-
- if (leaving->straight)
- {
- if (first == cluster->ba_count)
- first = i;
-
- last = i;
-
- if (straight_level < leaving->straight_level)
- {
- straight_level = leaving->straight_level;
- stop = leaving->other->owner;
- }
-
- }
-
- }
-
- if (stop != NULL)
- {
- if (first > 0)
- {
- pos[0] = G_MAXINT;
- pos[1] = 0;
-
- for (i = 0; i < first; i++)
- {
- leaving = cluster->bottom_anchors[i];
- g_graph_cluster_compute_min_max_horizontal(leaving->other->owner, stop, pos);
- }
-
- max = compute_leaving_link_position(cluster->bottom_anchors[first]);
-
- if ((pos[1] + LINK_MARGIN) > max)
- {
- cluster->right_offset = (pos[0] + LINK_MARGIN) - max;
- assert(false);
- }
-
- }
-
- if ((last + 1) < cluster->ba_count)
- {
- pos[0] = G_MAXINT;
- pos[1] = 0;
-
- for (i = last + 1; i < cluster->ba_count; i++)
- {
- leaving = cluster->bottom_anchors[i];
- g_graph_cluster_compute_min_max_horizontal(leaving->other->owner, stop, pos);
- }
-
- max = compute_leaving_link_position(cluster->bottom_anchors[last]);
-
- if ((max + LINK_MARGIN) > pos[0])
- cluster->right_offset = (max + LINK_MARGIN) - pos[0];
-
- }
-
- }
-
-}
-
-
-/******************************************************************************
-* *
* Paramètres : cluster = graphique de blocs à manipuler. *
* *
* Description : Réorganise au besoin les liens entrants d'un bloc. *
@@ -1604,7 +1915,6 @@ void g_graph_cluster_reorder_link_origins(GGraphCluster *cluster, bool left)
void g_graph_cluster_offset_x(GGraphCluster *cluster, gint offset)
{
size_t i; /* Boucle de parcours */
-
cluster->alloc.x += offset;
for (i = 0; i < cluster->ranks_count; i++)
@@ -1756,8 +2066,6 @@ void g_graph_cluster_compute_needed_alloc(const GGraphCluster *cluster, GtkAlloc
}
- alloc->width += cluster->right_offset;
-
}
@@ -2641,6 +2949,7 @@ GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList *
GHashTable *all; /* Collection des créations */
size_t count; /* Taille de la liste de blocs */
pending_blocks *pending; /* Suivi des blocs à traiter */
+ bool loop; /* Ordre de relance */
GtkAllocation needed; /* Taille requise */
/* Création des éléments */
@@ -2685,26 +2994,32 @@ GGraphCluster *bootstrap_graph_cluster(GLoadedBinary *binary, const GBlockList *
g_graph_cluster_sort_leaving_links(result);
/**
- * On vérifie maintenant que les liens bien verticaux ne rencontrent pas
- * de bloc de code.
+ * Un effet de bord de l'organisation en rangs de profondeur est que, dans
+ * une situation où les blocs sont placés de part et d'autre d'un lien vertical,
+ * ce lien vertical n'a d'influence que sur les blocs du même cluster.
+ *
+ * Les positions sont en effet déterminés via la fonction g_graph_cluster_dispatch_x().
*
- * Pour celà, il faut disposer d'une cartographie complète :
+ * Si un bloc d'un rang a des enfants qui ne sont pas dominés, la taille de
+ * ces enfants n'est pas prise en compte pour s'assurer du respect du lien
+ * vertical.
*
- * - sur l'axe des abscisses pour les positions à compenser.
- * - sur l'axe des ordonnées pour borner les suivis de liens en profondeur.
+ * On calcule ici un décalage de compensation. Et comme l'opération est de
+ * nature à réorganiser les blocs, on itère le nombre de fois nécessaires.
*/
- g_graph_cluster_reset_allocation(result);
-
- g_graph_cluster_dispatch_x(result);
+ do
+ {
+ g_graph_cluster_reset_allocation(result);
- g_graph_cluster_compute_needed_alloc(result, &needed);
+ g_graph_cluster_dispatch_x(result);
- g_graph_cluster_offset_x(result, -needed.x);
+ g_graph_cluster_set_y(result, 0);
- g_graph_cluster_set_y(result, 0);
+ loop = g_graph_cluster_dispatch_define_extra_offset(result);
- g_graph_cluster_ensure_space_for_straight(result);
+ }
+ while (loop);
/**
* A ce point, tous les blocs sont placés.