00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #define _GNU_SOURCE
00029
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <limits.h>
00038 #include <math.h>
00039
00040
00041
00042
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
00053
00054
00055 typedef struct _LineStrTab
00056 {
00057 ScbLineStyle style;
00058 char * name;
00059 } LineStrTab;
00060
00061
00062
00063
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
00080
00081
00082 static const double e = 0.001;
00083
00084
00085
00086
00087
00088
00089
00090
00091
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
00128 if (!erscribble_points_new(&ptr->points, ERSCRIBBLE_DEF_STROKE_POINTSIZE))
00129 {
00130
00131 g_free(ptr);
00132 return NULL;
00133 }
00134
00135
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
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
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
00161 if (!erscribble_points_new(&ptr->points, ERSCRIBBLE_DEF_STROKE_POINTSIZE))
00162 {
00163
00164 g_free(ptr);
00165 return NULL;
00166 }
00167
00168
00169 ptr->attributes = *pAttr;
00170
00171
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
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
00200
00201
00202
00203
00204
00205
00206 erscribble_points_append(&stroke->points, point);
00207
00208
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
00252
00253
00254
00255
00256 if (erscribble_driver_draw_now() || is_last_point)
00257 {
00258 if (is_last_point)
00259 {
00260
00261 erscribble_driver_draw_record(point,
00262 stroke->attributes.size_id,
00263 stroke->attributes.color,
00264 FALSE);
00265 }
00266
00267
00268 erscribble_driver_draw();
00269
00270
00271 erscribble_driver_draw_reset_context();
00272 }
00273
00274 if (!is_last_point)
00275 {
00276
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
00301 DrvPointInfo* op = &output.points[0];
00302 int i = 0;
00303 for(i = 0; i < len; ++i)
00304 {
00305
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;
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
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
00337
00338
00339
00340
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
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
00389
00390
00391
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
00419 int len = stroke->points.points->len;
00420 ScbPointPtr begin = (ScbPointPtr)stroke->points.points->data;
00421 ScbPointPtr end = begin;
00422
00423
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
00439 while (len > 1)
00440 {
00441 ++end;
00442 if (erscribble_is_lines_intersect((ScbPointPtr)&p1, (ScbPointPtr)&p2, begin, end))
00443 {
00444
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
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 }