scbstroke.c

Go to the documentation of this file.
00001 /*
00002  * File Name: scbstroke.c
00003  */
00004 
00005 /*
00006  * This file is part of liberscribble.
00007  *
00008  * liberscribble is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * liberscribble is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  */
00026 
00027 
00028 #define _GNU_SOURCE
00029 
00030 //----------------------------------------------------------------------------
00031 // Include Files
00032 //----------------------------------------------------------------------------
00033 
00034 // system include files, between < >
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <limits.h>
00038 #include <math.h>
00039 
00040 // ereader include files, between < >
00041 
00042 // local include files, between " "
00043 #include "scbutil.h"
00044 #include "scbtype.h"
00045 #include "scbstroke.h"
00046 #include "scblog.h"
00047 #include "scbconfig.h"
00048 #include "driver.h"
00049 
00050 
00051 //----------------------------------------------------------------------------
00052 // Type Declarations
00053 //----------------------------------------------------------------------------
00054 
00055 typedef struct _LineStrTab
00056 {
00057     ScbLineStyle    style;
00058     char *          name;
00059 } LineStrTab;
00060 
00061 
00062 //----------------------------------------------------------------------------
00063 // Global Constants
00064 //----------------------------------------------------------------------------
00065 
00066 #ifdef WIN32
00067 #define strcasecmp strcmp
00068 #endif
00069 
00070 const LineStrTab _Tab[] =
00071 {
00072     {ERSCRIBBLE_LINE_SOLID, "solid"},
00073     {ERSCRIBBLE_LINE_INVALID, ""},
00074 };
00075 
00076 const int LineTabSize = sizeof(_Tab)/sizeof(_Tab[0]);
00077 
00078 //----------------------------------------------------------------------------
00079 // Static Variables
00080 //----------------------------------------------------------------------------
00081 
00082 static const double e = 0.001;
00083 
00084 
00085 //============================================================================
00086 // Local Function Definitions
00087 //============================================================================
00088 
00089 
00090 //============================================================================
00091 // Functions Implementation
00092 //============================================================================
00093 
00094 const char *erscribble_line_style_to_str(const ScbLineStyle style)
00095 {
00096     int i;
00097     for(i = 0; i < LineTabSize; ++i)
00098     {
00099         if (style == _Tab[i].style)
00100         {
00101             return _Tab[i].name;
00102         }
00103     }
00104     return NULL;
00105 }
00106 
00107 
00108 ScbLineStyle erscribble_line_style_from_str(const char * str)
00109 {
00110     int i;
00111     for(i = 0; i < LineTabSize; ++i)
00112     {
00113         if (0 == strcasecmp(str, _Tab[i].name))
00114         {
00115             return _Tab[i].style;
00116         }
00117     }
00118     return ERSCRIBBLE_LINE_INVALID;
00119 }
00120 
00121 
00122 ScbStrokePtr erscribble_stroke_new()
00123 {
00124     ScbStrokePtr ptr = g_new0(ScbStroke, 1);
00125     ERSCRIBBLE_RET_NULL_IF(NULL == ptr, "Not enough memory for stroke!");
00126     
00127     // allocate points array
00128     if (!erscribble_points_new(&ptr->points, ERSCRIBBLE_DEF_STROKE_POINTSIZE))
00129     {
00130         // could not alloc memory for list
00131         g_free(ptr);
00132         return NULL;
00133     }
00134 
00135     // init the stroke paramters
00136     ptr->attributes.color     = ERSCRIBBLE_DEV_COLOR_BLACK;
00137     ptr->attributes.layer     = ERSCRIBBLE_DEF_STROKE_LAYER;
00138     ptr->attributes.shape_id  = ERSCRIBBLE_DEF_SHAPE_LINE;
00139     ptr->attributes.size_id   = ERSCRIBBLE_DEF_STROKE_PENSIZE;
00140 
00141     // init out bound rect. used to fast hit test
00142     ptr->rect.left   = INT_MAX;
00143     ptr->rect.top    = INT_MAX;
00144     ptr->rect.right  = INT_MIN;
00145     ptr->rect.bottom = INT_MIN;
00146 
00147     // init fast draw context 
00148     erscribble_driver_draw_reset_context();
00149     return ptr;
00150 }
00151 
00152 
00153 ScbStrokePtr erscribble_stroke_new_with_attributes(ScbStrokeAttributesPtr pAttr)
00154 {
00155     ERSCRIBBLE_RET_NULL_IF(NULL == pAttr, "Invalid pointer!");
00156 
00157     ScbStrokePtr ptr = g_new0(ScbStroke, 1);
00158     ERSCRIBBLE_RET_NULL_IF(NULL == ptr, "Not enough memory for stroke!");
00159     
00160     // allocate points array
00161     if (!erscribble_points_new(&ptr->points, ERSCRIBBLE_DEF_STROKE_POINTSIZE))
00162     {
00163         // could not alloc memory for list
00164         g_free(ptr);
00165         return NULL;
00166     }
00167 
00168     // init the stroke paramters
00169     ptr->attributes  = *pAttr;
00170 
00171     // init out bound rect. used to fast hit test
00172     ptr->rect.left   = INT_MAX;
00173     ptr->rect.top    = INT_MAX;
00174     ptr->rect.right  = INT_MIN;
00175     ptr->rect.bottom = INT_MIN;
00176 
00177     // init fast draw context 
00178     erscribble_driver_draw_reset_context();
00179     return ptr;
00180 }
00181 
00182 
00183 void erscribble_stroke_free(ScbStrokePtr stroke)
00184 {
00185     ERSCRIBBLE_RET_IF(NULL == stroke, "Attempt to release NULL pointer!");
00186     if (stroke->points.points)
00187     {
00188         erscribble_points_free(&stroke->points);
00189     }
00190     g_free(stroke);
00191 }
00192 
00193 
00194 int erscribble_stroke_add_point(ScbStrokePtr stroke, ScbDevPointPtr point)
00195 {
00196     ERSCRIBBLE_RET_INT_IF(NULL == stroke, ERSCRIBBLE_RET_ERR, "stroke pointer is NULL!");
00197     ERSCRIBBLE_RET_INT_IF(NULL == point, ERSCRIBBLE_RET_ERR, "Invalid point pointer!");
00198 
00199     // for debug. report points whose x or y is incorrect. 
00200     // It maybe not correct, the coordinates can be very large. 
00201     // if (point->x >=  1024 || point->y >= 1024)
00202     // {
00203         // WARNPRINTF("Odd points found! (%d %d)", point->x, point->y);
00204     // }
00205 
00206     erscribble_points_append(&stroke->points, point);
00207 
00208     // adjust rectangle
00209     if (stroke->rect.left > point->point.x)
00210     {
00211         stroke->rect.left = point->point.x;
00212     }
00213 
00214     if (stroke->rect.right < point->point.x)
00215     {
00216         stroke->rect.right = point->point.x;
00217     }
00218 
00219     if (stroke->rect.top > point->point.y)
00220     {
00221         stroke->rect.top = point->point.y;
00222     }
00223 
00224     if (stroke->rect.bottom < point->point.y)
00225     {
00226         stroke->rect.bottom = point->point.y;
00227     }
00228 
00229     return ERSCRIBBLE_RET_OK;
00230 }
00231 
00232 
00233 int erscribble_stroke_get_point_count(ScbStrokePtr stroke)
00234 {
00235     ERSCRIBBLE_RET_INT_IF(NULL == stroke || NULL == stroke->points.points, ERSCRIBBLE_INVALID_COUNT, "Invalid pointer(s)!");
00236     return stroke->points.points->len;
00237 }
00238 
00239 
00240 ScbPointPtr erscribble_stroke_get_point_data(ScbStrokePtr stroke)
00241 {
00242     ERSCRIBBLE_RET_NULL_IF(NULL == stroke, "Invalid pointer!");
00243     return erscribble_points_get_data(&stroke->points);
00244 }
00245 
00246 
00247 void erscribble_stroke_driver_draw_point(ScbStrokePtr stroke, ScbDevPointPtr point, gboolean is_last_point)
00248 {
00249     ERSCRIBBLE_RET_IF(NULL == stroke || NULL == point, "NULL storke or point!");
00250 
00251     // Fast draw points by using the additional global points buffer.
00252     // Here, we have two choices:
00253     // 1. use a timer, but the application should have a message loop. Gtk/X11
00254     // 2. check timestamp and points, draw them if necessary.
00255     
00256     if (erscribble_driver_draw_now() || is_last_point)
00257     {
00258         if (is_last_point)
00259         {
00260             // add the last point 
00261             erscribble_driver_draw_record(point, 
00262                 stroke->attributes.size_id,
00263                 stroke->attributes.color,
00264                 FALSE);
00265         }
00266 
00267         // draw it right now
00268         erscribble_driver_draw();
00269 
00270         // reset
00271         erscribble_driver_draw_reset_context();
00272     }
00273 
00274     if (!is_last_point)
00275     {
00276         // record this point
00277         erscribble_driver_draw_record(point,
00278             stroke->attributes.size_id,
00279             stroke->attributes.color, 
00280             TRUE);
00281     }
00282 }
00283 
00284 
00285 void erscribble_stroke_driver_draw(ScbStrokePtr stroke)
00286 {
00287     ERSCRIBBLE_RET_IF(NULL == stroke || NULL == stroke->points.points, "NULL pointer!");
00288 
00289     int len = stroke->points.points->len;
00290     if (len <= 0) return;
00291 
00292     ScbPointPtr ip = (ScbPointPtr)stroke->points.points->data;
00293 
00294     DrvPointsBuf output;
00295     int output_size = 0;
00296 
00297     int brush_size = stroke->attributes.size_id;
00298     unsigned char brush_color = stroke->attributes.color;
00299 
00300     // divide into ioctl's
00301     DrvPointInfo* op = &output.points[0];
00302     int i = 0;
00303     for(i = 0; i < len; ++i)
00304     {
00305         // copy points
00306         op->x = ip->x;
00307         op->y = ip->y;
00308         op->size = brush_size;
00309         op->color = brush_color;
00310         if (i == len-1) op->pen_down = FALSE; // force pen_up for last point of stroke
00311         else op->pen_down = TRUE;
00312 
00313         output_size++;
00314         ip++;
00315         op++;
00316 
00317         if (output_size == ERSCRIBBLE_DEF_DRIVER_DRAW_BUF_LEN || i == len-1)
00318         {
00319             // call ioctl
00320             output.count = output_size;
00321             erscribble_driver_draw_points(&output);
00322             output_size = 0;
00323             op = &output.points[0];
00324         }
00325     }
00326 }
00327 
00328 
00329 gboolean erscribble_stroke_point_hit_test(ScbStrokePtr stroke, 
00330                                    ScbDevPointPtr point,
00331                                    const ScbHitTestCtxPtr ctx)
00332 {
00333     ERSCRIBBLE_RET_FALSE_IF(NULL == stroke || NULL == point || NULL == ctx, 
00334         "Invalid pointer(s)!");
00335 
00336     // hit test
00337     // 1. check out bound and the point (fast check)
00338     // 2. check points in the stroke
00339 
00340     // fast check
00341     ScbRect tmp; 
00342     double ratio = 1.0;
00343     if (fabs(stroke->attributes.zoom - ctx->zoom) >= e)
00344     {
00345         ratio = stroke->attributes.zoom / ctx->zoom;
00346     }
00347     tmp.left    = point->point.x * ratio - ctx->size;
00348     tmp.right   = point->point.x * ratio + ctx->size;
00349     tmp.top     = point->point.y * ratio - ctx->size;
00350     tmp.bottom  = point->point.y * ratio + ctx->size;
00351     if (!erscribble_is_rect_intersect(&stroke->rect, &tmp))
00352     {
00353         return FALSE;
00354     }
00355 
00356     // check each point in stroke
00357     ScbRect src;
00358     int size = stroke->attributes.size_id;
00359     int len = stroke->points.points->len;
00360     ScbPointPtr pts = (ScbPointPtr)stroke->points.points->data;
00361     while (len)
00362     {
00363         src.left    = pts->x - size;
00364         src.right   = pts->x + size;
00365         src.top     = pts->y - size;
00366         src.bottom  = pts->y + size;
00367         if (erscribble_is_rect_intersect(&src, &tmp))
00368         {
00369             LOGPRINTF("\nrect1: (%d %d %d %d)\nrect2: (%d %d %d %d)",
00370                 src.left, src.top, src.right, src.bottom,
00371                 tmp.left, tmp.top, tmp.right, tmp.bottom);
00372             return TRUE;
00373         }
00374         ++pts; --len;
00375     }
00376     return FALSE;
00377 }
00378 
00379 
00380 gboolean erscribble_stroke_line_hit_test(ScbStrokePtr stroke, 
00381                                   ScbDevPointPtr point1,
00382                                   ScbDevPointPtr point2,
00383                                   const ScbHitTestCtxPtr ctx)
00384 {
00385     ERSCRIBBLE_RET_FALSE_IF(NULL == stroke || NULL == point1 || NULL == point2 || NULL == ctx, 
00386         "Invalid pointer(s)!");
00387 
00388     // check line and line segment in stroke
00389     // not consider the line width here...
00390     
00391     // fast check
00392     ScbRect tmp; 
00393     double ratio = 1.0;
00394     ScbDevPoint p1, p2;
00395     if (fabs(stroke->attributes.zoom - ctx->zoom) >= e)
00396     {
00397         ratio = stroke->attributes.zoom / ctx->zoom;
00398         p1.point.x = (int)point1->point.x * ratio;
00399         p1.point.y = (int)point1->point.y * ratio;
00400         p2.point.x = (int)point2->point.x * ratio;
00401         p2.point.y = (int)point2->point.y * ratio;
00402     }
00403     else
00404     {
00405         p1 = *point1; p2 = *point2;
00406     }
00407 
00408 
00409     tmp.left    = MIN(p1.point.x, p2.point.x) - ctx->size;
00410     tmp.right   = MAX(p1.point.x, p2.point.x) + ctx->size;
00411     tmp.top     = MIN(p1.point.y, p2.point.y) - ctx->size;
00412     tmp.bottom  = MAX(p1.point.y, p2.point.y) + ctx->size;
00413     if (!erscribble_is_rect_intersect(&stroke->rect, &tmp))
00414     {
00415         return FALSE;
00416     }
00417 
00418     // check each line segment in stroke
00419     int len = stroke->points.points->len;
00420     ScbPointPtr begin = (ScbPointPtr)stroke->points.points->data;
00421     ScbPointPtr end   = begin;
00422 
00423     // only one point
00424     if (len == 1)
00425     {
00426         if (erscribble_is_lines_intersect((ScbPointPtr)&p1, (ScbPointPtr)&p2, begin, end))
00427         {
00428             LOGPRINTF("one point hit!");
00429             LOGPRINTF("line in stroke: (%d %d) - (%d %d)", 
00430                 begin->x, begin->y, end->x, end->y);
00431             LOGPRINTF("user line: (%d %d) - (%d %d)",
00432                 p1.point.x, p1.point.y, p2.point.x, p2.point.y);
00433             return TRUE;
00434         }
00435         return FALSE;
00436     }
00437 
00438     // others
00439     while (len > 1)
00440     {
00441         ++end;
00442         if (erscribble_is_lines_intersect((ScbPointPtr)&p1, (ScbPointPtr)&p2, begin, end))
00443         {
00444             // for debug
00445             LOGPRINTF("line in stroke: (%d %d) - (%d %d)", 
00446                 begin->x, begin->y, end->x, end->y);
00447             LOGPRINTF("user line: (%d %d) - (%d %d)",
00448                 p1.point.x, p1.point.y, p2.point.x, p2.point.y);
00449             return TRUE;
00450         }
00451         begin = end; --len;
00452     }
00453     return FALSE;
00454 }
00455 
00456 
00457 gboolean erscribble_stroke_load(ScbStrokePtr stroke, ScbStreamPtr stream)
00458 {
00459     ERSCRIBBLE_RET_FALSE_IF(NULL == stroke || NULL == stream, "Invalid stroke pointer or stream!");
00460 
00461     gboolean ret = erscribble_read_stream(stream, &stroke->attributes, sizeof(stroke->attributes));
00462 
00463     if (ret == FALSE)
00464     {
00465         return ret;
00466     }
00467 
00468     ScbDevPoint point;
00469     int i = 0;
00470     for (; i < stroke->attributes.points_number; ++i)
00471     {
00472         if (erscribble_point_load(&point, stream) == FALSE)
00473         {
00474             return FALSE;
00475         }
00476 
00477         erscribble_stroke_add_point(stroke, &point);
00478     }
00479 
00480     return TRUE;
00481 }
00482 
00483 
00484 gboolean erscribble_stroke_write_stream(ScbStrokePtr stroke, ScbStreamPtr stream)
00485 {
00486     ERSCRIBBLE_RET_FALSE_IF(NULL == stroke || NULL == stream, "Invalid stroke pointer or stream!");
00487 
00488     if (erscribble_write_stream(stream, &stroke->attributes, sizeof(stroke->attributes)) == FALSE)
00489     {
00490         return FALSE;
00491     }
00492 
00493     int i = 0;
00494     for (; i < stroke->attributes.points_number; ++i)
00495     {
00496         ScbPoint point = g_array_index(stroke->points.points, ScbPoint, i);
00497         if (erscribble_write_stream(stream, &point, sizeof(ScbPoint)) == FALSE)
00498         {
00499             return FALSE;
00500         }
00501 
00502         int pressure = g_array_index(stroke->points.pressures, int, i);
00503         if (erscribble_write_stream(stream, &pressure, sizeof(int)) == FALSE)
00504         {
00505             return FALSE;
00506         }
00507     }
00508 
00509     return TRUE;
00510 }
00511 
00512 
00513 void erscribble_stroke_set_shape(ScbStrokePtr stroke, const int shape_id)
00514 {
00515     ERSCRIBBLE_RET_IF(NULL == stroke, "Invalid pointer!");
00516     stroke->attributes.shape_id = shape_id;
00517 }
00518 
00519 
00520 void erscribble_stroke_set_size(ScbStrokePtr stroke, const int size_id)
00521 {
00522     ERSCRIBBLE_RET_IF(NULL == stroke, "Invalid pointer!");
00523     stroke->attributes.size_id = size_id;
00524 }
00525 
00526 
00527 int erscribble_stroke_get_shape(ScbStrokePtr stroke)
00528 {
00529     if (NULL == stroke)
00530     {
00531         return ERSCRIBBLE_INVALID_SHAPE;
00532     }
00533 
00534     return stroke->attributes.shape_id;
00535 }
00536 
00537 
00538 int erscribble_stroke_get_size(ScbStrokePtr stroke)
00539 {
00540     if (NULL == stroke)
00541     {
00542         return ERSCRIBBLE_INVALID_SIZE;
00543     }
00544 
00545     return stroke->attributes.size_id;
00546 }
00547 
00548 
00549 void erscribble_stroke_dump(ScbStrokePtr ptr)
00550 {
00551     ERSCRIBBLE_RET_IF(NULL == ptr || NULL == ptr->points.points, "");
00552     
00553     int count = ptr->points.points->len;
00554     ScbPointPtr p = (ScbPointPtr)ptr->points.points->data;
00555     int *pp = (int *)ptr->points.pressures->data;
00556     while(count > 0)
00557     {
00558         DUMPPRINTF("\t(%d,\t%d,\t%d)", p->x, p->y, *pp);
00559         --count; ++ p; ++pp;
00560     }
00561 }
00562 
00563 //----------------------------------------------------------------------------
00564 // Deprecated functions
00565 //----------------------------------------------------------------------------
00566 
00567 void erscribble_stroke_set_color(ScbStrokePtr stroke, const ScbDevColor color)
00568 {
00569     ERSCRIBBLE_RET_IF(NULL == stroke, "Invalid pointer!");
00570     stroke->attributes.color = color;
00571 }
00572 
00573 
00574 ScbDevColor erscribble_stroke_get_color(ScbStrokePtr stroke)
00575 {
00576     if (NULL == stroke)
00577     {
00578         return ERSCRIBBLE_DEV_COLOR_UNKNOWN;
00579     }
00580     return stroke->attributes.color;
00581 }
Generated by  doxygen 1.6.2-20100208