Re: How to properly clip a gnome canvas item during render?



Hi Jason,

	If you only want to clip during the render stage there is a stock item
called GnomeCanvasClipgroup that you can use.  I found that this does
not really save on processor load as the render stage is relatively
cheap in terms of CPU time.

	If you are trying to save CPU cycles you should clip in the update
stage.  I did this a while ago with moderate success.  I was using all
stock canvas items so I overrode GnomeCanvasGroup, set the clip_svp in
its update method, then the group item passed the clip path to all of
the stock child items.  This of course only works for anti-aliased
canvas it has no effect on the gdk canvas.  I'm not sure if it will help
but I have pasted the code into this message.

	I had a lot of trouble with the SVPs.  For my use case I was drawing a
large number of very large polygons.  I would see various error messages
coming form the libart_lgpl library. Whenever the error messages came
up, the CPU processor time shot up.  You'll see calls to "perturb" the
vector path in various places.  By tweaking the amount of randomness in
this perturb function, the number if errors coming from libart can be
limited.  This has something to do with "numerical stability" of which I
understand nothing.

Regards.
Bob Gibbs



/*************************************************************************/
G_BEGIN_DECLS
                                                                                
/* GeoCanvasGroup is a small class the subclasses GnomeCanvasGroup in
order to
 * gain control of the clipping region.  When the geo area is zoomed
way-in
 * managing the overall scroll size and clipping the area to that scroll
size
 * helps to improve performance.
 */
                                                                                
#define GEO_TYPE_CANVAS_GROUP  (geo_canvas_group_get_type())
                                                                                
#define GEO_CANVAS_GROUP(obj) \
        (G_TYPE_CHECK_INSTANCE_CAST ((obj), \
        GEO_TYPE_CANVAS_GROUP, GeoCanvasGroup))
                                                                                
#define GEO_CANVAS_GROUP_CLASS(klass) \
        (G_TYPE_CHECK_CLASS_CAST ((klass), \
        GEO_TYPE_CANVAS_GROUP, GeoCanvasGroupClass))
                                                                                
#define GEO_IS_CANVAS_GROUP(obj) \
        (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GEO_TYPE_CANVAS_GROUP))
                                                                                
#define GEO_IS_CANVAS_GROUP_CLASS(klass) \
        (G_TYPE_CHECK_CLASS_TYPE ((klass), GEO_TYPE_CANVAS_GROUP))
                                                                                
#define GEO_CANVAS_GROUP_GET_CLASS(obj) \
        (G_TYPE_INSTANCE_GET_CLASS ((obj), \
        GEO_TYPE_CANVAS_GROUP, GeoCanvasGroupClass))
                                                                                
typedef struct _GeoCanvasGroup GeoCanvasGroup;
typedef struct _GeoCanvasGroupClass GeoCanvasGroupClass;
                                                                                
struct _GeoCanvasGroup
{
        GnomeCanvasGroup parent;
        ArtSVP *clip_svp;
};
                                                                                
struct _GeoCanvasGroupClass
{
        GnomeCanvasGroupClass parent_class;
};
                                                                                
GType geo_canvas_group_get_type(void);
                                                                                
void geo_canvas_group_update_clip(GeoCanvasGroup *group, gboolean
onoff);
                                                                                
G_END_DECLS
                                                                                
static GnomeCanvasGroup *geo_group_parent_class = NULL;
                                                                                void
geo_canvas_group_clip_to_scroll(GeoCanvasGroup *group, gboolean onoff)
{
        ArtVpath *vpath, *vpath2;
        GnomeCanvas *gnome_canvas = GNOME_CANVAS_ITEM(group)->canvas;
        double wx1, wy1, wx2, wy2, winx1, winy1, winx2, winy2;
                                                                                
        if (group->clip_svp) art_svp_free(group->clip_svp);
        group->clip_svp = NULL;
                                                                                
        if (onoff) {
                gnome_canvas_get_scroll_region(gnome_canvas, &wx1, &wy1,
                                &wx2, &wy2);
                                                                                
                gnome_canvas_world_to_window(gnome_canvas, wx1, wy1,
                                &winx1, &winy1);
                gnome_canvas_world_to_window(gnome_canvas, wx2, wy2,
                                &winx2, &winy2);
                                                                                
#ifdef DEBUG
                g_printf("new clip %lf %lf %lf %lf\n", winx1,
winy1,winx2,
                                winy2);
#endif
                                                                                
                vpath = art_new (ArtVpath, 6);
                vpath[0].code = ART_MOVETO;
                vpath[0].x = winx1;
                vpath[0].y = winy1;
                vpath[1].code = ART_LINETO;
                vpath[1].x = winx1;
                vpath[1].y = winy2;
                vpath[2].code = ART_LINETO;
                vpath[2].x = winx2;
                vpath[2].y = winy2;
                vpath[3].code = ART_LINETO;
                vpath[3].x = winx2;
                vpath[3].y = winy1;
                vpath[4].code = ART_LINETO;
                vpath[4].x = winx1;
                vpath[4].y = winy1;
                vpath[5].code = ART_END;
                vpath[5].x = 0.0;
                vpath[5].y = 0.0;
                                                                                
                vpath2 = art_vpath_perturb(vpath);
                group->clip_svp = art_svp_from_vpath (vpath2);
                art_free(vpath);
                art_free(vpath2);
        }
}
                                                                                static void
geo_canvas_group_init(GeoCanvasGroup *group)
{
}
                                                                                
static void
geo_canvas_group_update(GnomeCanvasItem *item, double *affine, ArtSVP
                *clip_svp, int flags)
{
        (*GNOME_CANVAS_ITEM_CLASS(geo_group_parent_class)->update)(item,
affine,                GEO_CANVAS_GROUP(item)->clip_svp, flags);
}
static void
geo_canvas_group_class_init(GeoCanvasGroupClass *klass)
{
        GnomeCanvasItemClass *item_class = NULL;
                                                                                
        item_class = (GnomeCanvasItemClass *) klass;
        geo_group_parent_class = g_type_class_peek_parent (klass);
                                                                                
        item_class->update = geo_canvas_group_update;
}
                                                                                
GType
geo_canvas_group_get_type(void)
{
        static GType type = 0;
        static const GTypeInfo info = {
                sizeof(GeoCanvasGroupClass),
                NULL, /*base_init*/
                NULL, /*base_finalize*/
                (GClassInitFunc) geo_canvas_group_class_init,
                (GClassFinalizeFunc) NULL,
                NULL,
                sizeof(GeoCanvasGroup),
                0,
                (GInstanceInitFunc) geo_canvas_group_init,
                NULL
        };
        if (!type) {
                type = g_type_register_static(GNOME_TYPE_CANVAS_GROUP,
                        "GeoCanvasGroup", &info, 0);
        }
        return type;
}





On Tue, 2004-02-10 at 14:39, The Surprises wrote:
> Hello,
> I am building a custom anti-aliased GnomeCanvasItem.  The item can be
> much larger than what is visible on the screen.  As such, I only want to
> compute the SVP of the visible portion of the item since it is
> inefficient to recompute the SVP every time an update is called.  I've
> read the gnomecanvas architecture docs, and I read that I need to set up
> the SVPs in the update method, then render to the pixbuf in the render
> method.  update takes an affine and a clip SVP as arguments.  Can I use
> either of these to compute the bbox of the portion of the item that
> needs to be redrawn?  I've looked at the source code for a couple of the
> canvas items, and I don't see any intelligent clipping being done (ie,
> for the canvas line, the SVP for the entire line is always generated
> regardless if there are segments fully outside the visible area).
> 
> Thanks for any help,
> Jason
> 
> 
> _______________________________________________
> gnome-devel-list mailing list
> gnome-devel-list gnome org
> http://mail.gnome.org/mailman/listinfo/gnome-devel-list




[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]