From 71636d01e3d75c0c6060e28c82487f472dd81602 Mon Sep 17 00:00:00 2001 From: Nicola Fontana Date: Wed, 9 Sep 2009 20:49:45 +0200 Subject: [PATCH] [AdgMarker] Using a custom local matrix The markers are not subject to the local maps, so the local_matrix() virtual method has been overriden to provide the needed transformations, that is translating, scaling and rotating accordling to the trail where the marker should be applied. --- adg/adg-marker.c | 118 ++++++++++++++++++++++++++++++++++++++++--------------- adg/adg-marker.h | 5 ++- 2 files changed, 89 insertions(+), 34 deletions(-) diff --git a/adg/adg-marker.c b/adg/adg-marker.c index db94beb2..da7ac9ff 100644 --- a/adg/adg-marker.c +++ b/adg/adg-marker.c @@ -72,12 +72,14 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); +static void get_local_matrix (AdgEntity *entity, + AdgMatrix *matrix); static gboolean invalidate (AdgEntity *entity); static gboolean set_trail (AdgMarker *marker, AdgTrail *trail); static void unset_trail (AdgMarker *marker); static gboolean set_n_segment (AdgMarker *marker, - gint n_segment); + guint n_segment); static gboolean set_pos (AdgMarker *marker, gdouble pos); static gboolean set_size (AdgMarker *marker, @@ -106,6 +108,7 @@ adg_marker_class_init(AdgMarkerClass *klass) gobject_class->set_property = set_property; gobject_class->get_property = get_property; + entity_class->get_local_matrix = get_local_matrix; entity_class->invalidate = invalidate; klass->create_model = create_model; @@ -114,27 +117,27 @@ adg_marker_class_init(AdgMarkerClass *klass) P_("Trail"), P_("The subject AdgTrail for this marker"), ADG_TYPE_TRAIL, - G_PARAM_CONSTRUCT|G_PARAM_READWRITE); + G_PARAM_READWRITE | G_PARAM_CONSTRUCT); g_object_class_install_property(gobject_class, PROP_TRAIL, param); param = g_param_spec_uint("n-segment", P_("Segment Index"), P_("The segment on trail where this marker should be applied (where 0 means undefined segment, 1 the first segment and so on)"), 0, G_MAXUINT, 0, - G_PARAM_CONSTRUCT|G_PARAM_READWRITE); + G_PARAM_READWRITE); g_object_class_install_property(gobject_class, PROP_N_SEGMENT, param); param = g_param_spec_double("pos", P_("Position"), P_("The position ratio inside the segment where to put the marker (0 means the start point while 1 means the end point)"), 0, 1, 0, - G_PARAM_CONSTRUCT|G_PARAM_READWRITE); + G_PARAM_READWRITE); g_object_class_install_property(gobject_class, PROP_POS, param); param = g_param_spec_double("size", P_("Marker Size"), P_("The size (in global space) of the marker"), - 0, G_MAXDOUBLE, 12, + 0, G_MAXDOUBLE, 10, G_PARAM_READWRITE); g_object_class_install_property(gobject_class, PROP_SIZE, param); @@ -286,7 +289,7 @@ adg_marker_set_trail(AdgMarker *marker, AdgTrail *trail) * * Returns: an index greather than %0 on success or %0 on errors **/ -gint +guint adg_marker_get_n_segment(AdgMarker *marker) { AdgMarkerPrivate *data; @@ -308,7 +311,7 @@ adg_marker_get_n_segment(AdgMarker *marker) * By convention, %1 is the first segment. **/ void -adg_marker_set_n_segment(AdgMarker *marker, gint n_segment) +adg_marker_set_n_segment(AdgMarker *marker, guint n_segment) { g_return_if_fail(ADG_IS_MARKER(marker)); @@ -327,13 +330,14 @@ adg_marker_set_n_segment(AdgMarker *marker, gint n_segment) * Gets the original segment where the marker has been applied. * Applying a marker could modify the underlying trail, usually * by trimming the original segment of a #AdgMarker:size dependent - * length from the end. The marker instance holds a copy of the - * original segment, got using adg_segment_deep_dup(), to be used - * in recomputation (when the marker changes size, for instance). + * length from the ends. The marker instance holds a copy of the + * original segment, generated by adg_marker_backup_segment(), + * to be used in recomputation, for example when the marker + * changes its size. * * When the subject segment is changed (either by changing * #AdgMarker:trail or #AdgMarker:n-segment) the original segment - * is restored. + * is automatically restored. * * Returns: the original segment or %NULL on errors **/ @@ -350,6 +354,46 @@ adg_marker_get_backup_segment(AdgMarker *marker) } /** + * adg_marker_backup_segment: + * @marker: an #AdgMarker + * + * + * This function is only useful in marker implementations. + * + * + * Duplicates the current subject segment for backup purpose: this + * segment can be accessed by adg_marker_get_backup_segment(). + * Obviously, a current segment should exist (either the + * #AdgMarker:trail and #AdgMarker:n-segment properties must be + * properly defined) or this method will fail without further + * processing. + * + * When the subject segment is changed (either by changing + * #AdgMarker:trail or #AdgMarker:n-segment) the original segment + * is automatically restored. + **/ +void +adg_marker_backup_segment(AdgMarker *marker) +{ + AdgMarkerPrivate *data; + + g_return_if_fail(ADG_IS_MARKER(marker)); + + data = marker->data; + + if (data->n_segment > 0) { + g_return_if_fail(data->trail != NULL); + + g_free(data->backup_segment); + + /* Backup the segment, if a segment to backup exists */ + if (adg_trail_get_segment(data->trail, + &data->segment, data->n_segment)) + data->backup_segment = adg_segment_deep_dup(&data->segment); + } +} + +/** * adg_marker_get_segment: * @marker: an #AdgMarker * @@ -532,6 +576,30 @@ adg_marker_set_model(AdgMarker *marker, AdgModel *model) } +static void +get_local_matrix(AdgEntity *entity, AdgMatrix *matrix) +{ + AdgMarkerPrivate *data; + CpmlPair pair; + CpmlVector vector; + AdgMatrix tmp; + + data = ((AdgMarker *) entity)->data; + cpml_segment_pair_at(&data->segment, &pair, data->pos); + cpml_segment_vector_at(&data->segment, &vector, data->pos); + cpml_vector_set_length(&vector, data->size); + + if (data->pos > 0.5) { + vector.x = -vector.x; + vector.y = -vector.y; + } + + cairo_matrix_init (&tmp, vector.x, vector.y, -vector.y, vector.x, 0, 0); + + cairo_matrix_init_translate(matrix, pair.x, pair.y); + cairo_matrix_multiply (matrix, &tmp, matrix); +} + static gboolean invalidate(AdgEntity *entity) { @@ -566,6 +634,7 @@ set_trail(AdgMarker *marker, AdgTrail *trail) } data->trail = trail; + data->n_segment = 0; if (data->trail != NULL) { g_object_weak_ref((GObject *) data->trail, @@ -591,40 +660,25 @@ unset_trail(AdgMarker *marker) } static gboolean -set_n_segment(AdgMarker *marker, gint n_segment) +set_n_segment(AdgMarker *marker, guint n_segment) { AdgMarkerPrivate *data = marker->data; if (n_segment == data->n_segment) return FALSE; - if (data->n_segment > 0) { - g_assert(data->backup_segment != NULL); - - /* Restore the original segment */ - adg_segment_deep_copy(&data->segment, data->backup_segment); - } - if (data->backup_segment != NULL) { + /* Restore the original segment, if any */ + if (data->trail != NULL) + adg_segment_deep_copy(&data->segment, data->backup_segment); + g_free(data->backup_segment); data->backup_segment = NULL; } - if (n_segment > 0) { - data->n_segment = 0; - g_return_val_if_fail(data->trail != NULL, FALSE); - - if (!adg_trail_get_segment(data->trail, - &data->segment, data->n_segment)) - return FALSE; - - /* Backup the segment */ - data->backup_segment = adg_segment_deep_dup(&data->segment); - } - data->n_segment = n_segment; - return TRUE; + return adg_trail_get_segment(data->trail, &data->segment, n_segment); } static gboolean diff --git a/adg/adg-marker.h b/adg/adg-marker.h index ce6094e4..d5dc9526 100644 --- a/adg/adg-marker.h +++ b/adg/adg-marker.h @@ -57,11 +57,12 @@ GType adg_marker_get_type (void) G_GNUC_CONST; AdgTrail * adg_marker_get_trail (AdgMarker *marker); void adg_marker_set_trail (AdgMarker *marker, AdgTrail *trail); -gint adg_marker_get_n_segment (AdgMarker *marker); +guint adg_marker_get_n_segment (AdgMarker *marker); void adg_marker_set_n_segment (AdgMarker *marker, - gint n_segment); + guint n_segment); const AdgSegment * adg_marker_get_backup_segment (AdgMarker *marker); +void adg_marker_backup_segment (AdgMarker *marker); AdgSegment * adg_marker_get_segment (AdgMarker *marker); gdouble adg_marker_get_pos (AdgMarker *marker); void adg_marker_set_pos (AdgMarker *marker, -- 2.11.4.GIT