diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2019-03-15 10:55:03 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2019-03-15 10:55:03 (GMT) |
commit | f65f83fd222d14934b527152899359327813128e (patch) | |
tree | 742e0f08a82ba941e386e5e3764a84b13e0c9ffe /src/gtkext/graph/cluster.c | |
parent | 0a190905f31d7c395e1b26efe3abe443687429e5 (diff) |
Tracked vertical links beyond their cluster.
Diffstat (limited to 'src/gtkext/graph/cluster.c')
-rw-r--r-- | src/gtkext/graph/cluster.c | 811 |
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. |