321 lines
6.2 KiB
C
321 lines
6.2 KiB
C
/******************************************************************************
|
|
* @file investigation_graph_layout.c
|
|
* @brief Implémentation du modèle en mémoire de disposition du graphe.
|
|
******************************************************************************/
|
|
|
|
#include "models/investigation_graph_layout.h"
|
|
|
|
#include <math.h>
|
|
|
|
/**
|
|
* @brief Coordonnées privées associées à un nœud.
|
|
*/
|
|
typedef struct
|
|
{
|
|
double x;
|
|
double y;
|
|
} InvestigationGraphLayoutPosition;
|
|
|
|
/**
|
|
* @struct InvestigationGraphLayout
|
|
* @brief Représentation privée de la disposition.
|
|
*/
|
|
struct InvestigationGraphLayout
|
|
{
|
|
GHashTable *positions_by_node_identifier;
|
|
};
|
|
|
|
/**
|
|
* @brief Enregistre une erreur littérale.
|
|
*/
|
|
static void investigation_graph_layout_set_error_literal(
|
|
GError **error,
|
|
InvestigationGraphLayoutError error_code,
|
|
const char *error_message
|
|
)
|
|
{
|
|
if (error == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_set_error_literal(
|
|
error,
|
|
INVESTIGATION_GRAPH_LAYOUT_ERROR,
|
|
error_code,
|
|
error_message
|
|
);
|
|
}
|
|
|
|
/**
|
|
* @brief Vérifie un identifiant de nœud.
|
|
*/
|
|
static gboolean investigation_graph_layout_identifier_is_valid(
|
|
const char *node_identifier
|
|
)
|
|
{
|
|
return node_identifier != NULL &&
|
|
node_identifier[0] != '\0' &&
|
|
g_uuid_string_is_valid(
|
|
node_identifier
|
|
);
|
|
}
|
|
|
|
GQuark investigation_graph_layout_error_quark(void)
|
|
{
|
|
return g_quark_from_static_string(
|
|
"investigation-graph-layout-error-quark"
|
|
);
|
|
}
|
|
|
|
InvestigationGraphLayout *investigation_graph_layout_new(void)
|
|
{
|
|
InvestigationGraphLayout *layout =
|
|
NULL;
|
|
|
|
layout =
|
|
g_try_new0(
|
|
InvestigationGraphLayout,
|
|
1
|
|
);
|
|
|
|
if (layout == NULL)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
layout->positions_by_node_identifier =
|
|
g_hash_table_new_full(
|
|
g_str_hash,
|
|
g_str_equal,
|
|
g_free,
|
|
g_free
|
|
);
|
|
|
|
if (layout->positions_by_node_identifier == NULL)
|
|
{
|
|
investigation_graph_layout_free(
|
|
layout
|
|
);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return layout;
|
|
}
|
|
|
|
gboolean investigation_graph_layout_set_position(
|
|
InvestigationGraphLayout *layout,
|
|
const char *node_identifier,
|
|
double x,
|
|
double y,
|
|
GError **error
|
|
)
|
|
{
|
|
InvestigationGraphLayoutPosition *position =
|
|
NULL;
|
|
|
|
char *node_identifier_copy =
|
|
NULL;
|
|
|
|
g_return_val_if_fail(
|
|
error == NULL || *error == NULL,
|
|
FALSE
|
|
);
|
|
|
|
if (layout == NULL ||
|
|
layout->positions_by_node_identifier == NULL)
|
|
{
|
|
investigation_graph_layout_set_error_literal(
|
|
error,
|
|
INVESTIGATION_GRAPH_LAYOUT_ERROR_INVALID_ARGUMENT,
|
|
"La disposition du graphe est absente."
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (!investigation_graph_layout_identifier_is_valid(
|
|
node_identifier
|
|
))
|
|
{
|
|
investigation_graph_layout_set_error_literal(
|
|
error,
|
|
INVESTIGATION_GRAPH_LAYOUT_ERROR_INVALID_IDENTIFIER,
|
|
"L'identifiant du nœud n'est pas un UUID valide."
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
if (!isfinite(x) ||
|
|
!isfinite(y))
|
|
{
|
|
investigation_graph_layout_set_error_literal(
|
|
error,
|
|
INVESTIGATION_GRAPH_LAYOUT_ERROR_INVALID_COORDINATE,
|
|
"Les coordonnées du nœud doivent être des nombres finis."
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
node_identifier_copy =
|
|
g_strdup(
|
|
node_identifier
|
|
);
|
|
|
|
position =
|
|
g_try_new0(
|
|
InvestigationGraphLayoutPosition,
|
|
1
|
|
);
|
|
|
|
if (node_identifier_copy == NULL ||
|
|
position == NULL)
|
|
{
|
|
g_free(
|
|
position
|
|
);
|
|
|
|
g_free(
|
|
node_identifier_copy
|
|
);
|
|
|
|
investigation_graph_layout_set_error_literal(
|
|
error,
|
|
INVESTIGATION_GRAPH_LAYOUT_ERROR_MEMORY,
|
|
"Impossible d'allouer la position du nœud."
|
|
);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
position->x =
|
|
x;
|
|
|
|
position->y =
|
|
y;
|
|
|
|
g_hash_table_replace(
|
|
layout->positions_by_node_identifier,
|
|
node_identifier_copy,
|
|
position
|
|
);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean investigation_graph_layout_get_position(
|
|
const InvestigationGraphLayout *layout,
|
|
const char *node_identifier,
|
|
double *x,
|
|
double *y
|
|
)
|
|
{
|
|
const InvestigationGraphLayoutPosition *position =
|
|
NULL;
|
|
|
|
if (layout == NULL ||
|
|
layout->positions_by_node_identifier == NULL ||
|
|
!investigation_graph_layout_identifier_is_valid(
|
|
node_identifier
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
position =
|
|
g_hash_table_lookup(
|
|
layout->positions_by_node_identifier,
|
|
node_identifier
|
|
);
|
|
|
|
if (position == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
if (x != NULL)
|
|
{
|
|
*x =
|
|
position->x;
|
|
}
|
|
|
|
if (y != NULL)
|
|
{
|
|
*y =
|
|
position->y;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
gboolean investigation_graph_layout_remove_position(
|
|
InvestigationGraphLayout *layout,
|
|
const char *node_identifier
|
|
)
|
|
{
|
|
if (layout == NULL ||
|
|
layout->positions_by_node_identifier == NULL ||
|
|
!investigation_graph_layout_identifier_is_valid(
|
|
node_identifier
|
|
))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return g_hash_table_remove(
|
|
layout->positions_by_node_identifier,
|
|
node_identifier
|
|
);
|
|
}
|
|
|
|
void investigation_graph_layout_clear(
|
|
InvestigationGraphLayout *layout
|
|
)
|
|
{
|
|
if (layout == NULL ||
|
|
layout->positions_by_node_identifier == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_hash_table_remove_all(
|
|
layout->positions_by_node_identifier
|
|
);
|
|
}
|
|
|
|
guint investigation_graph_layout_get_count(
|
|
const InvestigationGraphLayout *layout
|
|
)
|
|
{
|
|
if (layout == NULL ||
|
|
layout->positions_by_node_identifier == NULL)
|
|
{
|
|
return 0U;
|
|
}
|
|
|
|
return g_hash_table_size(
|
|
layout->positions_by_node_identifier
|
|
);
|
|
}
|
|
|
|
void investigation_graph_layout_free(
|
|
InvestigationGraphLayout *layout
|
|
)
|
|
{
|
|
if (layout == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
g_clear_pointer(
|
|
&layout->positions_by_node_identifier,
|
|
g_hash_table_unref
|
|
);
|
|
|
|
g_free(
|
|
layout
|
|
);
|
|
}
|