diff options
| author | Andrew Higginson <at.higginson@gmail.com> | 2011-12-27 21:04:47 +0000 |
|---|---|---|
| committer | Andrew <at.higginson@gmail.com> | 2011-12-27 21:04:47 +0000 |
| commit | 80960b623a99aae1402ab651b2974ef544ed3b03 (patch) | |
| tree | ba49d42c2789e9e11f805e2d5263e10f9fedeef8 /src/display/guideline.cpp | |
| parent | try to fix bug (diff) | |
| parent | GDL: Cherry-pick upstream patch 73852 (2011-03-23) - Add missing return value. (diff) | |
| download | inkscape-80960b623a99aae1402ab651b2974ef544ed3b03.tar.gz inkscape-80960b623a99aae1402ab651b2974ef544ed3b03.zip | |
merged with trunk so I can build again...
(bzr r10092.1.36)
Diffstat (limited to 'src/display/guideline.cpp')
| -rw-r--r-- | src/display/guideline.cpp | 239 |
1 files changed, 91 insertions, 148 deletions
diff --git a/src/display/guideline.cpp b/src/display/guideline.cpp index bebec2852..f2802c6fe 100644 --- a/src/display/guideline.cpp +++ b/src/display/guideline.cpp @@ -13,12 +13,16 @@ * Released under GNU GPL, read the file 'COPYING' for more information */ - -#include <libnr/nr-pixops.h> +#include <2geom/coord.h> #include <2geom/transforms.h> #include "sp-canvas-util.h" #include "sp-ctrlpoint.h" #include "guideline.h" +#include "display/cairo-utils.h" + +#include "inkscape.h" // for inkscape_active_desktop() +#include "desktop.h" +#include "sp-namedview.h" static void sp_guideline_class_init(SPGuideLineClass *c); static void sp_guideline_init(SPGuideLine *guideline); @@ -78,6 +82,7 @@ static void sp_guideline_init(SPGuideLine *gl) gl->sensitive = 0; gl->origin = NULL; + gl->label = NULL; } static void sp_guideline_destroy(GtkObject *object) @@ -99,88 +104,84 @@ static void sp_guideline_destroy(GtkObject *object) static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf) { - SPGuideLine const *gl = SP_GUIDELINE (item); - - sp_canvas_prepare_buffer(buf); - - unsigned int const r = NR_RGBA32_R (gl->rgba); - unsigned int const g = NR_RGBA32_G (gl->rgba); - unsigned int const b = NR_RGBA32_B (gl->rgba); - unsigned int const a = NR_RGBA32_A (gl->rgba); + //TODO: the routine that renders the label of a specific guideline sometimes + // ends up erasing the labels of the other guidelines. + // Maybe we should render all labels everytime. - if (gl->is_vertical()) { - int position = (int) Inkscape::round(gl->point_on_line[Geom::X]); - if (position < buf->rect.x0 || position >= buf->rect.x1) { - return; - } - - int p0 = buf->rect.y0; - int p1 = buf->rect.y1; - int step = buf->buf_rowstride; - unsigned char *d = buf->buf + 4 * (position - buf->rect.x0); - - for (int p = p0; p < p1; p++) { - d[0] = NR_COMPOSEN11_1111(r, a, d[0]); - d[1] = NR_COMPOSEN11_1111(g, a, d[1]); - d[2] = NR_COMPOSEN11_1111(b, a, d[2]); - d += step; - } - } else if (gl->is_horizontal()) { - int position = (int) Inkscape::round(gl->point_on_line[Geom::Y]); - if (position < buf->rect.y0 || position >= buf->rect.y1) { - return; - } + SPGuideLine const *gl = SP_GUIDELINE (item); - int p0 = buf->rect.x0; - int p1 = buf->rect.x1; - int step = 4; - unsigned char *d = buf->buf + (position - buf->rect.y0) * buf->buf_rowstride; + cairo_save(buf->ct); + cairo_translate(buf->ct, -buf->rect.left(), -buf->rect.top()); + ink_cairo_set_source_rgba32(buf->ct, gl->rgba); + cairo_set_line_width(buf->ct, 1); + cairo_set_line_cap(buf->ct, CAIRO_LINE_CAP_SQUARE); + cairo_set_font_size(buf->ct, 10); + + Geom::Point normal_dt = /*unit_vector*/(gl->normal_to_line * gl->affine.withoutTranslation()); // note that normal_dt does not have unit length + Geom::Point point_on_line_dt = gl->point_on_line * gl->affine; + + if (gl->label) { + int px = round(point_on_line_dt[Geom::X]); + int py = round(point_on_line_dt[Geom::Y]); + cairo_save(buf->ct); + cairo_translate(buf->ct, px, py); + cairo_rotate(buf->ct, atan2(normal_dt.cw())); + cairo_translate(buf->ct, 0, -5); + cairo_move_to(buf->ct, 0, 0); + cairo_show_text(buf->ct, gl->label); + cairo_restore(buf->ct); + } - for (int p = p0; p < p1; p++) { - d[0] = NR_COMPOSEN11_1111(r, a, d[0]); - d[1] = NR_COMPOSEN11_1111(g, a, d[1]); - d[2] = NR_COMPOSEN11_1111(b, a, d[2]); - d += step; - } + if ( Geom::are_near(normal_dt[Geom::Y], 0.) ) { // is vertical? + int position = round(point_on_line_dt[Geom::X]); + cairo_move_to(buf->ct, position + 0.5, buf->rect.top() + 0.5); + cairo_line_to(buf->ct, position + 0.5, buf->rect.bottom() - 0.5); + cairo_stroke(buf->ct); + } else if ( Geom::are_near(normal_dt[Geom::X], 0.) ) { // is horizontal? + int position = round(point_on_line_dt[Geom::Y]); + cairo_move_to(buf->ct, buf->rect.left() + 0.5, position + 0.5); + cairo_line_to(buf->ct, buf->rect.right() - 0.5, position + 0.5); + cairo_stroke(buf->ct); } else { - // render angled line, once intersection has been detected, draw from there. - Geom::Point parallel_to_line( gl->normal_to_line[Geom::Y], - /*should be minus, but inverted y axis*/ gl->normal_to_line[Geom::X]); + // render angled line. Once intersection has been detected, draw from there. + Geom::Point parallel_to_line( normal_dt.ccw() ); //try to intersect with left vertical of rect - double y_intersect_left = (buf->rect.x0 - gl->point_on_line[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + gl->point_on_line[Geom::Y]; - if ( (y_intersect_left >= buf->rect.y0) && (y_intersect_left <= buf->rect.y1) ) { + double y_intersect_left = (buf->rect.left() - point_on_line_dt[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + point_on_line_dt[Geom::Y]; + if ( (y_intersect_left >= buf->rect.top()) && (y_intersect_left <= buf->rect.bottom()) ) { // intersects with left vertical! - double y_intersect_right = (buf->rect.x1 - gl->point_on_line[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + gl->point_on_line[Geom::Y]; - sp_guideline_drawline (buf, buf->rect.x0, static_cast<gint>(round(y_intersect_left)), buf->rect.x1, static_cast<gint>(round(y_intersect_right)), gl->rgba); - return; + double y_intersect_right = (buf->rect.right() - point_on_line_dt[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + point_on_line_dt[Geom::Y]; + sp_guideline_drawline (buf, buf->rect.left(), static_cast<gint>(round(y_intersect_left)), buf->rect.right(), static_cast<gint>(round(y_intersect_right)), gl->rgba); + goto end; } //try to intersect with right vertical of rect - double y_intersect_right = (buf->rect.x1 - gl->point_on_line[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + gl->point_on_line[Geom::Y]; - if ( (y_intersect_right >= buf->rect.y0) && (y_intersect_right <= buf->rect.y1) ) { + double y_intersect_right = (buf->rect.right() - point_on_line_dt[Geom::X]) * parallel_to_line[Geom::Y] / parallel_to_line[Geom::X] + point_on_line_dt[Geom::Y]; + if ( (y_intersect_right >= buf->rect.top()) && (y_intersect_right <= buf->rect.bottom()) ) { // intersects with right vertical! - sp_guideline_drawline (buf, buf->rect.x1, static_cast<gint>(round(y_intersect_right)), buf->rect.x0, static_cast<gint>(round(y_intersect_left)), gl->rgba); - return; + sp_guideline_drawline (buf, buf->rect.right(), static_cast<gint>(round(y_intersect_right)), buf->rect.left(), static_cast<gint>(round(y_intersect_left)), gl->rgba); + goto end; } //try to intersect with top horizontal of rect - double x_intersect_top = (buf->rect.y0 - gl->point_on_line[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + gl->point_on_line[Geom::X]; - if ( (x_intersect_top >= buf->rect.x0) && (x_intersect_top <= buf->rect.x1) ) { + double x_intersect_top = (buf->rect.top() - point_on_line_dt[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + point_on_line_dt[Geom::X]; + if ( (x_intersect_top >= buf->rect.left()) && (x_intersect_top <= buf->rect.right()) ) { // intersects with top horizontal! - double x_intersect_bottom = (buf->rect.y1 - gl->point_on_line[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + gl->point_on_line[Geom::X]; - sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_top)), buf->rect.y0, static_cast<gint>(round(x_intersect_bottom)), buf->rect.y1, gl->rgba); - return; + double x_intersect_bottom = (buf->rect.bottom() - point_on_line_dt[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + point_on_line_dt[Geom::X]; + sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_top)), buf->rect.top(), static_cast<gint>(round(x_intersect_bottom)), buf->rect.bottom(), gl->rgba); + goto end; } //try to intersect with bottom horizontal of rect - double x_intersect_bottom = (buf->rect.y1 - gl->point_on_line[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + gl->point_on_line[Geom::X]; - if ( (x_intersect_top >= buf->rect.x0) && (x_intersect_top <= buf->rect.x1) ) { + double x_intersect_bottom = (buf->rect.bottom() - point_on_line_dt[Geom::Y]) * parallel_to_line[Geom::X] / parallel_to_line[Geom::Y] + point_on_line_dt[Geom::X]; + if ( (x_intersect_top >= buf->rect.left()) && (x_intersect_top <= buf->rect.right()) ) { // intersects with bottom horizontal! - sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_bottom)), buf->rect.y1, static_cast<gint>(round(x_intersect_top)), buf->rect.y0, gl->rgba); - return; + sp_guideline_drawline (buf, static_cast<gint>(round(x_intersect_bottom)), buf->rect.bottom(), static_cast<gint>(round(x_intersect_top)), buf->rect.top(), gl->rgba); + goto end; } } + end: + cairo_restore(buf->ct); } static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, unsigned int flags) @@ -191,17 +192,18 @@ static void sp_guideline_update(SPCanvasItem *item, Geom::Affine const &affine, ((SPCanvasItemClass *) parent_class)->update(item, affine, flags); } - gl->point_on_line[Geom::X] = affine[4]; - gl->point_on_line[Geom::Y] = affine[5]; + gl->affine = affine; - sp_ctrlpoint_set_coords(gl->origin, gl->point_on_line * affine.inverse()); + sp_ctrlpoint_set_coords(gl->origin, gl->point_on_line); sp_canvas_item_request_update(SP_CANVAS_ITEM (gl->origin)); + Geom::Point pol_transformed = gl->point_on_line*affine; if (gl->is_horizontal()) { - sp_canvas_update_bbox (item, -1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y]), 1000000, (int) Inkscape::round(gl->point_on_line[Geom::Y] + 1)); + sp_canvas_update_bbox (item, -1000000, round(pol_transformed[Geom::Y] - 16), 1000000, round(pol_transformed[Geom::Y] + 1)); } else if (gl->is_vertical()) { - sp_canvas_update_bbox (item, (int) Inkscape::round(gl->point_on_line[Geom::X]), -1000000, (int) Inkscape::round(gl->point_on_line[Geom::X] + 1), 1000000); + sp_canvas_update_bbox (item, round(pol_transformed[Geom::X]), -1000000, round(pol_transformed[Geom::X] + 16), 1000000); } else { + //TODO: labels in angled guidelines are not showing up for some reason. sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000); } } @@ -212,17 +214,17 @@ static double sp_guideline_point(SPCanvasItem *item, Geom::Point p, SPCanvasItem SPGuideLine *gl = SP_GUIDELINE (item); if (!gl->sensitive) { - return NR_HUGE; + return Geom::infinity(); } *actual_item = item; - Geom::Point vec(gl->normal_to_line[Geom::X], - gl->normal_to_line[Geom::Y]); - double distance = Geom::dot((p - gl->point_on_line), vec); + Geom::Point vec = gl->normal_to_line * gl->affine.withoutTranslation(); + double distance = Geom::dot((p - gl->point_on_line * gl->affine), unit_vector(vec)); return MAX(fabs(distance)-1, 0); } -SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, Geom::Point point_on_line, Geom::Point normal) +SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, char* label, Geom::Point point_on_line, Geom::Point normal) { SPCanvasItem *item = sp_canvas_item_new(parent, SP_TYPE_GUIDELINE, NULL); SPCanvasItem *origin = sp_canvas_item_new(parent, SP_TYPE_CTRLPOINT, NULL); @@ -232,6 +234,7 @@ SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, Geom::Point point_on_line, gl->origin = cp; normal.normalize(); + gl->label = label; gl->normal_to_line = normal; gl->angle = tan( -gl->normal_to_line[Geom::X] / gl->normal_to_line[Geom::Y]); sp_guideline_set_position(gl, point_on_line); @@ -241,10 +244,20 @@ SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, Geom::Point point_on_line, return item; } +void sp_guideline_set_label(SPGuideLine *gl, const char* label) +{ + if (gl->label) { + g_free(gl->label); + } + gl->label = g_strdup(label); + + sp_canvas_item_request_update(SP_CANVAS_ITEM (gl)); +} + void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line) { - sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl), Geom::Affine(Geom::Translate(point_on_line))); - sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl->origin), Geom::Affine(Geom::Translate(point_on_line))); + gl->point_on_line = point_on_line; + sp_canvas_item_request_update(SP_CANVAS_ITEM (gl)); } void sp_guideline_set_normal(SPGuideLine *gl, Geom::Point normal_to_line) @@ -274,82 +287,12 @@ void sp_guideline_delete(SPGuideLine *gl) gtk_object_destroy(GTK_OBJECT(gl)); } -//########################################################## -// Line rendering -#define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params - -/** - \brief This function renders a pixel on a particular buffer. - - The topleft of the buffer equals - ( rect.x0 , rect.y0 ) in screen coordinates - ( 0 , 0 ) in setpixel coordinates - The bottomright of the buffer equals - ( rect.x1 , rect,y1 ) in screen coordinates - ( rect.x1 - rect.x0 , rect.y1 - rect.y0 ) in setpixel coordinates -*/ -static void -sp_guideline_setpixel (SPCanvasBuf *buf, gint x, gint y, guint32 rgba) -{ -#ifdef SAFE_SETPIXEL - if ( (x >= buf->rect.x0) && (x < buf->rect.x1) && (y >= buf->rect.y0) && (y < buf->rect.y1) ) { -#endif - guint r, g, b, a; - r = NR_RGBA32_R (rgba); - g = NR_RGBA32_G (rgba); - b = NR_RGBA32_B (rgba); - a = NR_RGBA32_A (rgba); - guchar * p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 4; - p[0] = NR_COMPOSEN11_1111 (r, a, p[0]); - p[1] = NR_COMPOSEN11_1111 (g, a, p[1]); - p[2] = NR_COMPOSEN11_1111 (b, a, p[2]); -#ifdef SAFE_SETPIXEL - } -#endif -} - -/** - \brief This function renders a line on a particular canvas buffer, - using Bresenham's line drawing function. - http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html - Coordinates are interpreted as SCREENcoordinates -*/ static void -sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba) +sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 /*rgba*/) { - int dy = y1 - y0; - int dx = x1 - x0; - int stepx, stepy; - - if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; } - if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; } - dy <<= 1; // dy is now 2*dy - dx <<= 1; // dx is now 2*dx - - sp_guideline_setpixel(buf, x0, y0, rgba); - if (dx > dy) { - int fraction = dy - (dx >> 1); // same as 2*dy - dx - while (x0 != x1) { - if (fraction >= 0) { - y0 += stepy; - fraction -= dx; // same as fraction -= 2*dx - } - x0 += stepx; - fraction += dy; // same as fraction -= 2*dy - sp_guideline_setpixel(buf, x0, y0, rgba); - } - } else { - int fraction = dx - (dy >> 1); - while (y0 != y1) { - if (fraction >= 0) { - x0 += stepx; - fraction -= dy; - } - y0 += stepy; - fraction += dx; - sp_guideline_setpixel(buf, x0, y0, rgba); - } - } + cairo_move_to(buf->ct, x0 + 0.5, y0 + 0.5); + cairo_line_to(buf->ct, x1 + 0.5, y1 + 0.5); + cairo_stroke(buf->ct); } /* |
