correction to mrp-assignment.c patch
Lee Baylis <lee-gZngeWTYz/[email protected]> Mon, 01 Dec 2008 01:07:25 +0000
| Newsgroups | gmane.comp.gnome.apps.planner.devel |
|---|---|
| Message-ID | <[email protected]> |
Hi all, apologies - the recent patch I submitted for mrp-assignment.c doesn't take account of the asymmetrical nature of 'units_in_use' (i.e., units_in_use stores units to the right of an edge). As a result, whilst the code for mrp_assignment_edges_remove_from_first_after does exactly what it says, it is not a useful routine to deploy in resource overallocation calculations. I have replaced the function with the simpler mrp_assignment_edges_remove_after, which is more useful. Hopefully this will get through before those patches make it to commit! Also attached are the updated call to the function in mrp-resource.c, as well as the header and changelog. Sorry about that! lee _______________________________________________ Planner-dev-list mailing list [email protected] http://mail.gnome.org/mailman/listinfo/planner-dev-list
ChangeLog.patch
(text/x-diff, 2 KB)
Index: ChangeLog =================================================================== --- ChangeLog (revision 940) +++ ChangeLog (working copy) @@ -1,3 +1,40 @@ +2008-11-28 Lee Baylis <lee-gZngeWTYz/[email protected]> + + * libplanner/mrp-assignment.c (assignment_edge_compare), + (mrp_assignment_edges_insert_sorted_from_assignment), + (mrp_assignment_edges_insert_sorted_from_assignment_list), + (mrp_assignment_edges_plot_units_in_use), + (mrp_assignment_edges_calculate_max_units_in_use), + (mrp_assignment_edges_remove_to_last_before), + (mrp_assignment_edges_remove_after), + (mrp_assignment_edge_get_delta_units): + Moved and changed Date struct from planner-usage-row to become + MrpAssignmentEdge struct; + Introduced functions for creating and manipulating lists of + MrpAssignmentEdge objects. + * libplanner/mrp-assignment.h: + * libplanner/mrp-resource.c (mrp_resource_get_assignment_edges), + (mrp_resource_allocation_status), + (mrp_resource_test_if_overallocated), + (resource_get_edges_with_units_in_use), + (mrp_resource_get_max_units_used_between), + (mrp_resource_get_available_units_between), + (mrp_resource_get_available_units_during): + Moved logic for calculating overallocation from planner-usage-row; + Introduced functions for listing and analysing a resource's + MrpAssignmentEdge objects; + Introduced resource overallocation test function. + * libplanner/mrp-resource.h: + * src/planner-usage-row.c (usage_row_realize), + (usage_row_draw_resource_ival), (usage_row_draw_resource), + (usage_row_draw_assignment): + Moved Date & date_type structs and the date_compare + function to mrp-assignment; + Moved code which initialised Dates to mrp-assignment; + Replaced 12 color variables with 4 color_scheme structs + and matched them to overallocation scenarios; + Moved logic for calculating overallocation to mrp-resource. + 2008-11-05 Maurice van der Pot <griffon26-bCGDfOjggl9Wk0Htik3J/[email protected]> * libplanner/mrp-parser.c: Removed unused function.
mrp-assignment.c.patch
(text/x-diff, 8.8 KB)
Index: libplanner/mrp-assignment.c =================================================================== --- libplanner/mrp-assignment.c (revision 940) +++ libplanner/mrp-assignment.c (working copy) @@ -3,6 +3,7 @@ * Copyright (C) 2001-2003 CodeFactory AB * Copyright (C) 2001-2003 Richard Hult <[email protected]> * Copyright (C) 2001-2002 Mikael Hallendal <[email protected]> + * Copyright (C) 2008 Lee Baylis <lee-gZngeWTYz/[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -43,19 +44,20 @@ PROP_UNITS }; +static void assignment_class_init (MrpAssignmentClass *klass); +static void assignment_init (MrpAssignment *assignment); +static void assignment_finalize (GObject *object); +static void assignment_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void assignment_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static gint assignment_edge_compare (gconstpointer edge1, + gconstpointer edge2); -static void assignment_class_init (MrpAssignmentClass *klass); -static void assignment_init (MrpAssignment *assignment); -static void assignment_finalize (GObject *object); -static void assignment_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void assignment_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); - static MrpObjectClass *parent_class; GType @@ -226,6 +228,33 @@ } } +static gint +assignment_edge_compare (gconstpointer edge1, + gconstpointer edge2) +{ + const MrpAssignmentEdge *a, *b; + + a = edge1; + b = edge2; + + if (a->time < b->time) { + return -1; + } + else if (a->time == b->time) { + /* if times are equal, overallocation calculations require that end_edges are sorted before start_edges */ + if (a->type < b->type) { + return 1; + } + else if (a->type == b->type) { + return 0; + } else { + return -1; + } + } else { + return 1; + } +} + /** * mrp_assignment_new: * @@ -267,8 +296,8 @@ * * Retrieves the #MrpResource associated with @assignment. * - * Return value: the resource associated with the assignment object. The reference - * count of the resource is not increased. + * Return value: the resource associated with the assignment object. + * The reference count of the resource is not increased. **/ MrpResource * mrp_assignment_get_resource (MrpAssignment *assignment) @@ -294,3 +323,210 @@ return assignment->priv->units; } + +/** + * mrp_assignment_edges_insert_sorted_from_assignment: + * @edges: a #GList optionally containing #MrpAssignmentEdge objects + * @assignment: an #MrpAssignment + * + * Determines the start and end edges (essentially times + assignment units) + * from an assignment's associated task, and inserts them into the list of + * edges sorted by mrptime. Mostly useful for tracking a MrpResource's + * total assignment units whilst scanning across a project. + * + * Return Value: pointer to the updated edges GList. + **/ +GList * +mrp_assignment_edges_insert_sorted_from_assignment (GList *edges, + MrpAssignment *assignment) +{ + MrpTask *task; + gint units; + MrpAssignmentEdge *start_edge, *end_edge; + + g_return_val_if_fail (MRP_IS_ASSIGNMENT (assignment), edges); + + task = mrp_assignment_get_task (assignment); + units = mrp_assignment_get_units (assignment); + + start_edge = g_new0 (MrpAssignmentEdge, 1); + start_edge->type = START_EDGE; + start_edge->time = mrp_task_get_work_start(task); + start_edge->units = units; + start_edge->assignment = assignment; + start_edge->task = task; + + edges = g_list_insert_sorted (edges, start_edge, assignment_edge_compare); + + end_edge = g_new0 (MrpAssignmentEdge, 1); + end_edge->type = END_EDGE; + end_edge->time = mrp_task_get_finish(task); + end_edge->units = units; + end_edge->assignment = assignment; + end_edge->task = task; + + edges = g_list_insert_sorted (edges, end_edge, assignment_edge_compare); + + return edges; +} + +/** + * mrp_assignment_edges_insert_sorted_from_assignment_list: + * @edges: a #GList containing #MrpAssignmentEdge objects + * @assignments: a #GList contianing #MrpAssignment objects + * + * Determines the sorted start and end edges for all passed assignments. + * Mostly useful for scanning a #MrpResource object's total assignment + * units across a project. + * + * Return Value: pointer to the updated edges #GList. + **/ +GList * +mrp_assignment_edges_insert_sorted_from_assignment_list (GList *edges, + GList *assignments) +{ + GList *a; + MrpAssignment *assignment; + + for (a = assignments; a; a = a->next) { + assignment = a->data; + edges = mrp_assignment_edges_insert_sorted_from_assignment(edges, assignment); + } + return edges; +} + +/** + * mrp_assignment_edges_plot_units_in_use: + * @edges: a #GList containing #MrpAssignmentEdge objects + * + * Iterates the #GList of #MrpAssignmentEdge objects calculating a + * running total for each #MrpAssignmentEdge by adding units for + * start edges and subtracting them for end edges. Mostly useful for + * calculating a #MrpResource object's allocation within a period. + * + * Return Value: pointer to the updated edges #GList. + **/ +GList * +mrp_assignment_edges_plot_units_in_use (GList *edges) +{ + GList *e; + MrpAssignmentEdge *edge; + gint units = 0; + + for (e = edges; e; e = e->next) { + edge = e->data; + units += mrp_assignment_edge_get_delta_units(edge); + edge->units_in_use = units; + } + return edges; +} + +/** + * mrp_assignment_edges_calculate_max_units_in_use: + * @edges: a #GList containing #MrpAssignmentEdge objects + * + * Iterates the #GList of #MrpAssignmentEdge objects consulting the + * running total for each #MrpAssignmentEdge and storing the maximum. + * + * Return Value: #gint containing the maximum units in use. + **/ +gint +mrp_assignment_edges_calculate_max_units_in_use (GList *edges) +{ + GList *e; + MrpAssignmentEdge *edge; + gint units = 0; + + for (e = edges; e; e = e->next){ + edge = e->data; + if (edge->units_in_use > units) { + units = edge->units_in_use; + } + } + return units; +} + +/** + * mrp_assignment_edges_remove_to_last_before: + * @edges: a #GList containing #MrpAssignmentEdge objects + * @time: a #mrptime + * + * Removes all but the last #MrpAssignmentEdge object before @time from @edges. + * Mostly useful for isolating time periods for later calculation. + * + * Return Value: pointer to the updated edges #GList. + **/ +GList * +mrp_assignment_edges_remove_to_last_before(GList *edges, + mrptime time) +{ + GList *e; + MrpAssignmentEdge *edge; + + if (edges){ + e = edges->next; + if (e){ + edge = e->data; + while (edge->time <= time){ + edges = g_list_delete_link(edges, edges); + e = edges->next; + if (!e) {break;} + edge = e->data; + } + } + } + return edges; +} + +/** + * mrp_assignment_edges_remove_after: + * @edges: a #GList containing #MrpAssignmentEdge objects + * @time: a #mrptime + * + * Removes all #MrpAssignmentEdge objects after @time from @edges. + * Mostly useful for isolating time periods for later calculation. + * + * Return Value: pointer to the updated edges #GList. + **/ +GList * +mrp_assignment_edges_remove_after(GList *edges, + mrptime time) +{ + GList *last; + MrpAssignmentEdge *edge; + + if (edges){ + last = g_list_last(edges); + if (last){ + edge = last->data; + while (time <= edge->time){ + edges = g_list_delete_link(edges, last); + last = g_list_last(edges); + if (!last) {break;} + edge = last->data; + } + } + } + + return edges; +} + +/** + * mrp_assignment_edge_get_delta_units: + * @edge: a #MrpAssignmentEdge + * + * Edge-sensing function: returns the change in units associated with + * an assignment, either signed positive for a start edge, or negative + * for an end edge. + * + * Return Value: gint representing the change in assignment units at the edge. + **/ +gint +mrp_assignment_edge_get_delta_units (MrpAssignmentEdge *edge) +{ + if (edge->type == START_EDGE) { + return edge->units; + } else { + return 0 - edge->units; + } +}
mrp-assignment.h.patch
(text/x-diff, 2.9 KB)
Index: libplanner/mrp-assignment.h =================================================================== --- libplanner/mrp-assignment.h (revision 940) +++ libplanner/mrp-assignment.h (working copy) @@ -3,6 +3,7 @@ * Copyright (C) 2001-2002 CodeFactory AB * Copyright (C) 2001-2002 Richard Hult <[email protected]> * Copyright (C) 2001-2002 Mikael Hallendal <[email protected]> + * Copyright (C) 2008 Lee Baylis <lee-gZngeWTYz/[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -36,6 +37,8 @@ typedef struct _MrpAssignmentClass MrpAssignmentClass; typedef struct _MrpAssignmentPriv MrpAssignmentPriv; +typedef enum _MrpAssignmentEdgeType MrpAssignmentEdgeType; +typedef struct _MrpAssignmentEdge MrpAssignmentEdge; struct _MrpAssignment { MrpObject parent; @@ -47,12 +50,36 @@ MrpObjectClass parent_class; }; -GType mrp_assignment_get_type (void) G_GNUC_CONST; +enum _MrpAssignmentEdgeType{ + START_EDGE, + END_EDGE +}; -MrpAssignment *mrp_assignment_new (void); +struct _MrpAssignmentEdge { + MrpAssignmentEdgeType type; + mrptime time; + gint units; + gint units_in_use; + MrpAssignment *assignment; + MrpTask *task; +}; -MrpTask *mrp_assignment_get_task (MrpAssignment *assignment); -MrpResource *mrp_assignment_get_resource (MrpAssignment *assignment); -gint mrp_assignment_get_units (MrpAssignment *assignment); +GType mrp_assignment_get_type (void) G_GNUC_CONST; +MrpAssignment *mrp_assignment_new (void); + +MrpTask *mrp_assignment_get_task (MrpAssignment *assignment); +MrpResource *mrp_assignment_get_resource (MrpAssignment *assignment); +gint mrp_assignment_get_units (MrpAssignment *assignment); +GList * mrp_assignment_edges_insert_sorted_from_assignment (GList *edges, + MrpAssignment *assignment); +GList * mrp_assignment_edges_insert_sorted_from_assignment_list (GList *edges, + GList *assignments); +GList * mrp_assignment_edges_plot_units_in_use (GList *edges); +gint mrp_assignment_edges_calculate_max_units_in_use (GList *edges); +GList * mrp_assignment_edges_remove_to_last_before (GList *edges, + mrptime time); +GList * mrp_assignment_edges_remove_after (GList *edges, + mrptime time); +gint mrp_assignment_edge_get_delta_units (MrpAssignmentEdge *edge); #endif /* __MRP_ASSIGNMENT_H__ */
mrp-resource.c.patch
(text/x-diff, 9.4 KB)
Index: libplanner/mrp-resource.c =================================================================== --- libplanner/mrp-resource.c (revision 940) +++ libplanner/mrp-resource.c (working copy) @@ -5,6 +5,7 @@ * Copyright (C) 2002-2003 Richard Hult <[email protected]> * Copyright (C) 2002 Mikael Hallendal <[email protected]> * Copyright (C) 2004 Alvaro del Castillo <[email protected]> + * Copyright (C) 2008 Lee Baylis <lee-gZngeWTYz/[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -32,6 +33,9 @@ #include "mrp-task.h" #include "mrp-resource.h" +/* Constant for usage calculations +FIXME: need to alter the UI so that users can set the priv->units value per resource, then can remove this constant */ +#define USAGE_MAX_UNITS 100 struct _MrpResourcePriv { gchar *name; @@ -69,25 +73,27 @@ }; -static void resource_class_init (MrpResourceClass *klass); -static void resource_init (MrpResource *resource); -static void resource_finalize (GObject *object); -static void resource_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec); -static void resource_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec); -static void resource_calendar_changed (MrpCalendar *calendar, - MrpResource *resource); -static void resource_removed (MrpObject *object); -static void resource_invalidate_task_costs (MrpResource *resource); -static void resource_assignment_removed_cb (MrpAssignment *assignment, - MrpResource *resource); -static void resource_group_removed_cb (MrpGroup *group, - MrpResource *resource); +static void resource_class_init (MrpResourceClass *klass); +static void resource_init (MrpResource *resource); +static void resource_finalize (GObject *object); +static void resource_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); +static void resource_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void resource_calendar_changed (MrpCalendar *calendar, + MrpResource *resource); +static void resource_removed (MrpObject *object); +static void resource_invalidate_task_costs (MrpResource *resource); +static void resource_assignment_removed_cb (MrpAssignment *assignment, + MrpResource *resource); +static void resource_group_removed_cb (MrpGroup *group, + MrpResource *resource); +static GList *resource_get_edges_with_units_in_use (MrpResource *resource, + GList *edges); static MrpObjectClass *parent_class; @@ -826,3 +832,206 @@ g_object_set (resource, "calendar", calendar, NULL); } + +/* There are two ways to look for overallocation: + + - the first is to chart a running total of a resource's allocation + across the whole project, and scan through it looking for total values + of allocation at either a time or some condition. + + This is the technique previously adopted in planner-usage-row, + now moved here and embellished upon. + + - The second is to scan a resource's allocations for those which are + active at a given time, and add up the usage. Whilst this is likely a + more efficient method for larger projects, we are rarely interested in + an individual time, more usually a period between two times, and so it + is not clear right now whether implementing this second will be of any use. +*/ + +/** + * mrp_resource_get_assignment_edges: + * @resource: a #MrpResource + * @edges: a #GList optionally containing #MrpAssignmentEdge objects + * + * Adds all the assignment edges for the resource to the edges glist, + * sorted by mrptime. Usually you want this list to be empty before + * calling this function. Free the edges list when done. Mostly useful + * for calculating total resource allocation over the project. + * + * Return Value: the updated edges GList + **/ +GList * +mrp_resource_get_assignment_edges (MrpResource *resource, + GList *edges) +{ + GList *assignments; + g_return_val_if_fail (MRP_IS_RESOURCE (resource), edges); + + assignments = mrp_resource_get_assignments (resource); + edges = mrp_assignment_edges_insert_sorted_from_assignment_list(edges, assignments); + + return edges; +} + +/** + * mrp_resource_allocation_status: + * @resource: a #MrpResource + * @units: a #gint + * + * Lookup table for allocation status based on the number of units of a + * resource which are allocated + * + * Return Value: an entry from the MrpResourceAllocation enum + **/ +MrpResourceAllocation +mrp_resource_allocation_status (MrpResource *resource, gint units) +{ + g_return_val_if_fail (MRP_IS_RESOURCE (resource), MRP_RESOURCE_OVERALLOCATED); +/* FIXME: replace USAGE_MAX_UNITS on a per-resource basis rather than a defined constant */ + if (units == 0) { + return MRP_RESOURCE_FREE; + } + else if (units < USAGE_MAX_UNITS) { + return MRP_RESOURCE_UNDERALLOCATED; + } + else if (units == USAGE_MAX_UNITS) { + return MRP_RESOURCE_ALLOCATED; + } else { + return MRP_RESOURCE_OVERALLOCATED; + } +} + +/** + * mrp_resource_test_if_overallocated: + * @resource: a #MrpResource + * + * Scans the project duration for the resource and determines if it is + * ever overallocated. + * + * Return Value: gboolean inidcating whether resource is ever overallocated + **/ +gboolean +mrp_resource_test_if_overallocated (MrpResource *resource) +{ + gint units; + + g_return_val_if_fail (MRP_IS_RESOURCE (resource), TRUE); + + units = mrp_resource_get_max_units_used_between(resource, NULL, NULL); + + if (mrp_resource_allocation_status(resource, units) == MRP_RESOURCE_OVERALLOCATED){ + return TRUE; + } + return FALSE; +} + +/** + * resource_get_edges_with_units_in_use: + * @resource: a #MrpResource + * + * Return Value: a GList of MrpAssignmentEdge objects with the running total + * of units in use calculated. + * + **/ +GList * +resource_get_edges_with_units_in_use (MrpResource *resource, + GList *edges) +{ + g_return_val_if_fail (MRP_IS_RESOURCE (resource), edges); + + edges = mrp_resource_get_assignment_edges(resource, edges); + edges = mrp_assignment_edges_plot_units_in_use(edges); + + return edges; +} + + +/** + * mrp_resource_get_max_units_used_between: + * @resource: a #MrpResource + * @start: a #mrptime marking the start of a period, or project start if #NULL + * @end: a #mrptime marking the end of a period, or project end if #NULL + * + * Plots cumulative allocation for the resource across the project, + * then scans between the start and end times given, and calculates + * the maximum allocation in this period. + * + * Return Value: gint indicating the maximum units which have been allocated + * to the resource in this period. + **/ + +gint +mrp_resource_get_max_units_used_between (MrpResource *resource, + mrptime start, + mrptime end) +{ + GList *edges = NULL; + gint units; + + /* FIXME: replace USAGE_MAX_UNITS on a per-resource basis rather than a defined constant */ + g_return_val_if_fail (MRP_IS_RESOURCE (resource), USAGE_MAX_UNITS + 1); + + edges = resource_get_edges_with_units_in_use(resource, edges); + + if (start){ + edges = mrp_assignment_edges_remove_to_last_before(edges, start); + } + if (end){ + edges = mrp_assignment_edges_remove_after(edges, end); + } + + units = mrp_assignment_edges_calculate_max_units_in_use(edges); + + g_list_free(edges); + + return units; +} + +/** + * mrp_resource_get_available_units_between: + * @resource: a #MrpResource + * @start: a #mrptime + * @end: a #mrptime + * + * Return Value: gint indicating the maximum units which are available + * for the resource in this period without causing overallocation. + **/ +gint +mrp_resource_get_available_units_between (MrpResource *resource, + mrptime start, + mrptime end) +{ +/* FIXME: replace USAGE_MAX_UNITS on a per-resource basis rather than a defined constant */ + g_return_val_if_fail (MRP_IS_RESOURCE (resource), -1); + /* gint available; + + available =*/ + return USAGE_MAX_UNITS - mrp_resource_get_max_units_used_between(resource, start, end); + + /* if (available < 0){ + available = 0; + } + return available;*/ +} + +/** + * mrp_resource_get_available_units_during: + * @resource: a #MrpResource + * @task: a #MrpTask + * + * Return Value: gint indicating the maximum units which are available + * for the resource between the times the task is running, without + * causing overallocation. + **/ +gint +mrp_resource_get_available_units_during (MrpResource *resource, + MrpTask *task) +{ + g_return_val_if_fail (MRP_IS_RESOURCE (resource), -1); + g_return_val_if_fail (MRP_IS_TASK (task), -1); + + return mrp_resource_get_available_units_between(resource, + mrp_task_get_work_start(task), + mrp_task_get_finish(task)); +}