1 #define __SP_GUIDELINE_C__
3 /*
4 * Horizontal/vertical but can also be angled line
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 * Johan Engelen
9 *
10 * Copyright (C) 2000-2002 Lauris Kaplinski
11 * Copyright (C) 2007 Johan Engelen
12 *
13 * Released under GNU GPL, read the file 'COPYING' for more information
14 */
17 #include <libnr/nr-pixops.h>
18 #include "display-forward.h"
19 #include "sp-canvas-util.h"
20 #include "guideline.h"
22 static void sp_guideline_class_init(SPGuideLineClass *c);
23 static void sp_guideline_init(SPGuideLine *guideline);
24 static void sp_guideline_destroy(GtkObject *object);
26 static void sp_guideline_update(SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
27 static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf);
29 static double sp_guideline_point(SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item);
31 static void sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba);
33 static SPCanvasItemClass *parent_class;
35 GType sp_guideline_get_type()
36 {
37 static GType guideline_type = 0;
39 if (!guideline_type) {
40 static GTypeInfo const guideline_info = {
41 sizeof (SPGuideLineClass),
42 NULL, NULL,
43 (GClassInitFunc) sp_guideline_class_init,
44 NULL, NULL,
45 sizeof (SPGuideLine),
46 16,
47 (GInstanceInitFunc) sp_guideline_init,
48 NULL,
49 };
51 guideline_type = g_type_register_static(SP_TYPE_CANVAS_ITEM, "SPGuideLine", &guideline_info, (GTypeFlags) 0);
52 }
54 return guideline_type;
55 }
57 static void sp_guideline_class_init(SPGuideLineClass *c)
58 {
59 parent_class = (SPCanvasItemClass*) g_type_class_peek_parent(c);
61 GtkObjectClass *object_class = (GtkObjectClass *) c;
62 object_class->destroy = sp_guideline_destroy;
64 SPCanvasItemClass *item_class = (SPCanvasItemClass *) c;
65 item_class->update = sp_guideline_update;
66 item_class->render = sp_guideline_render;
67 item_class->point = sp_guideline_point;
68 }
70 static void sp_guideline_init(SPGuideLine *gl)
71 {
72 gl->rgba = 0x0000ff7f;
74 gl->normal_to_line = Geom::Point(0,1);
75 gl->point_on_line = Geom::Point(0,0);
76 gl->sensitive = 0;
77 }
79 static void sp_guideline_destroy(GtkObject *object)
80 {
81 GTK_OBJECT_CLASS(parent_class)->destroy(object);
82 }
84 static void sp_guideline_render(SPCanvasItem *item, SPCanvasBuf *buf)
85 {
86 SPGuideLine const *gl = SP_GUIDELINE (item);
88 sp_canvas_prepare_buffer(buf);
90 unsigned int const r = NR_RGBA32_R (gl->rgba);
91 unsigned int const g = NR_RGBA32_G (gl->rgba);
92 unsigned int const b = NR_RGBA32_B (gl->rgba);
93 unsigned int const a = NR_RGBA32_A (gl->rgba);
95 if (gl->normal_to_line[Geom::Y] == 0.) {
96 int position = gl->point_on_line[Geom::X];
97 if (position < buf->rect.x0 || position >= buf->rect.x1) {
98 return;
99 }
101 int p0 = buf->rect.y0;
102 int p1 = buf->rect.y1;
103 int step = buf->buf_rowstride;
104 unsigned char *d = buf->buf + 3 * (position - buf->rect.x0);
106 for (int p = p0; p < p1; p++) {
107 d[0] = NR_COMPOSEN11_1111(r, a, d[0]);
108 d[1] = NR_COMPOSEN11_1111(g, a, d[1]);
109 d[2] = NR_COMPOSEN11_1111(b, a, d[2]);
110 d += step;
111 }
112 } else if (gl->normal_to_line[Geom::X] == 0.) {
113 int position = gl->point_on_line[Geom::Y];
114 if (position < buf->rect.y0 || position >= buf->rect.y1) {
115 return;
116 }
118 int p0 = buf->rect.x0;
119 int p1 = buf->rect.x1;
120 int step = 3;
121 unsigned char *d = buf->buf + (position - buf->rect.y0) * buf->buf_rowstride;
123 for (int p = p0; p < p1; p++) {
124 d[0] = NR_COMPOSEN11_1111(r, a, d[0]);
125 d[1] = NR_COMPOSEN11_1111(g, a, d[1]);
126 d[2] = NR_COMPOSEN11_1111(b, a, d[2]);
127 d += step;
128 }
129 } else {
130 // render angled line
131 }
132 }
134 static void sp_guideline_update(SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
135 {
136 SPGuideLine *gl = SP_GUIDELINE(item);
138 if (((SPCanvasItemClass *) parent_class)->update) {
139 ((SPCanvasItemClass *) parent_class)->update(item, affine, flags);
140 }
142 gl->point_on_line[Geom::X] = affine[4] +0.5;
143 gl->point_on_line[Geom::Y] = affine[5] -0.5;
145 if (gl->normal_to_line[Geom::Y] == 1.) {
146 sp_canvas_update_bbox (item, -1000000, gl->point_on_line[Geom::Y], 1000000, gl->point_on_line[Geom::Y] + 1);
147 } else if (gl->normal_to_line[Geom::X] == 1.) {
148 sp_canvas_update_bbox (item, gl->point_on_line[Geom::X], -1000000, gl->point_on_line[Geom::X]+1, 1000000);
149 } else {
150 sp_canvas_update_bbox (item, -1000000, -1000000, 1000000, 1000000);
151 }
152 }
154 // Returns 0.0 if point is on the guideline
155 static double sp_guideline_point(SPCanvasItem *item, NR::Point p, SPCanvasItem **actual_item)
156 {
157 SPGuideLine *gl = SP_GUIDELINE (item);
159 if (!gl->sensitive) {
160 return NR_HUGE;
161 }
163 *actual_item = item;
165 double distance = Geom::dot((p.to_2geom() - gl->point_on_line), gl->normal_to_line);
166 return MAX(fabs(distance)-1, 0);
167 }
169 SPCanvasItem *sp_guideline_new(SPCanvasGroup *parent, Geom::Point point_on_line, Geom::Point normal)
170 {
171 SPCanvasItem *item = sp_canvas_item_new(parent, SP_TYPE_GUIDELINE, NULL);
173 SPGuideLine *gl = SP_GUIDELINE(item);
175 normal.normalize();
176 gl->normal_to_line = normal;
177 sp_guideline_set_position(gl, point_on_line);
179 return item;
180 }
182 void sp_guideline_set_position(SPGuideLine *gl, Geom::Point point_on_line)
183 {
184 sp_canvas_item_affine_absolute(SP_CANVAS_ITEM (gl),
185 NR::Matrix(NR::translate(point_on_line)));
186 }
188 void sp_guideline_set_normal(SPGuideLine *gl, Geom::Point normal_to_line)
189 {
190 gl->normal_to_line = normal_to_line;
191 sp_canvas_item_request_update(SP_CANVAS_ITEM (gl));
192 }
194 void sp_guideline_set_color(SPGuideLine *gl, unsigned int rgba)
195 {
196 gl->rgba = rgba;
198 sp_canvas_item_request_update(SP_CANVAS_ITEM(gl));
199 }
201 void sp_guideline_set_sensitive(SPGuideLine *gl, int sensitive)
202 {
203 gl->sensitive = sensitive;
204 }
206 //##########################################################
207 // Line rendering
208 #define SAFE_SETPIXEL //undefine this when it is certain that setpixel is never called with invalid params
210 /**
211 \brief This function renders a pixel on a particular buffer.
213 The topleft of the buffer equals
214 ( rect.x0 , rect.y0 ) in screen coordinates
215 ( 0 , 0 ) in setpixel coordinates
216 The bottomright of the buffer equals
217 ( rect.x1 , rect,y1 ) in screen coordinates
218 ( rect.x1 - rect.x0 , rect.y1 - rect.y0 ) in setpixel coordinates
219 */
220 static void
221 sp_guideline_setpixel (SPCanvasBuf *buf, gint x, gint y, guint32 rgba)
222 {
223 #ifdef SAFE_SETPIXEL
224 if ( (x >= buf->rect.x0) && (x < buf->rect.x1) && (y >= buf->rect.y0) && (y < buf->rect.y1) ) {
225 #endif
226 guint r, g, b, a;
227 r = NR_RGBA32_R (rgba);
228 g = NR_RGBA32_G (rgba);
229 b = NR_RGBA32_B (rgba);
230 a = NR_RGBA32_A (rgba);
231 guchar * p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3;
232 p[0] = NR_COMPOSEN11_1111 (r, a, p[0]);
233 p[1] = NR_COMPOSEN11_1111 (g, a, p[1]);
234 p[2] = NR_COMPOSEN11_1111 (b, a, p[2]);
235 #ifdef SAFE_SETPIXEL
236 }
237 #endif
238 }
240 /**
241 \brief This function renders a line on a particular canvas buffer,
242 using Bresenham's line drawing function.
243 http://www.cs.unc.edu/~mcmillan/comp136/Lecture6/Lines.html
244 Coordinates are interpreted as SCREENcoordinates
245 */
246 static void
247 sp_guideline_drawline (SPCanvasBuf *buf, gint x0, gint y0, gint x1, gint y1, guint32 rgba)
248 {
249 int dy = y1 - y0;
250 int dx = x1 - x0;
251 int stepx, stepy;
253 if (dy < 0) { dy = -dy; stepy = -1; } else { stepy = 1; }
254 if (dx < 0) { dx = -dx; stepx = -1; } else { stepx = 1; }
255 dy <<= 1; // dy is now 2*dy
256 dx <<= 1; // dx is now 2*dx
258 sp_guideline_setpixel(buf, x0, y0, rgba);
259 if (dx > dy) {
260 int fraction = dy - (dx >> 1); // same as 2*dy - dx
261 while (x0 != x1) {
262 if (fraction >= 0) {
263 y0 += stepy;
264 fraction -= dx; // same as fraction -= 2*dx
265 }
266 x0 += stepx;
267 fraction += dy; // same as fraction -= 2*dy
268 sp_guideline_setpixel(buf, x0, y0, rgba);
269 }
270 } else {
271 int fraction = dx - (dy >> 1);
272 while (y0 != y1) {
273 if (fraction >= 0) {
274 x0 += stepx;
275 fraction -= dy;
276 }
277 y0 += stepy;
278 fraction += dx;
279 sp_guideline_setpixel(buf, x0, y0, rgba);
280 }
281 }
282 }
284 /*
285 Local Variables:
286 mode:c++
287 c-file-style:"stroustrup"
288 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
289 indent-tabs-mode:nil
290 fill-column:99
291 End:
292 */
293 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :