00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00024 #define _GNU_SOURCE
00025
00026 #include <stdio.h>
00027 #include <strings.h>
00028 #include <limits.h>
00029 #include <math.h>
00030
00031 #include "scbutil.h"
00032 #include "scbtype.h"
00033 #include "scbstroke.h"
00034 #include "scblog.h"
00035 #include "scbconfig.h"
00036 #include "driver.h"
00037
00038 static const double e = 0.001;
00039
00040
00041
00042
00043 static const int SCB_DEF_BOUNDARY_LEFT = 0;
00044 static const int SCB_DEF_BOUNDARY_TOP = 0;
00045 static const int SCB_DEF_BOUNDARY_RIGHT = 768;
00046 static const int SCB_DEF_BOUNDARY_BOTTOM = 935;
00047
00048
00049
00050 typedef struct _LineStrTab
00051 {
00052 ScbLineStyle style;
00053 char * name;
00054 }LineStrTab;
00055
00056
00057 const LineStrTab _Tab[] =
00058 {
00059 {SCB_LINE_SOLID, "solid"},
00060 {SCB_LINE_INVALID, ""},
00061 };
00062 const int LineTabSize = sizeof(_Tab)/sizeof(_Tab[0]);
00063
00064
00065
00066 const char * scb_line_style_to_str(const ScbLineStyle style)
00067 {
00068 int i;
00069 for(i = 0; i < LineTabSize; ++i)
00070 {
00071 if (style == _Tab[i].style)
00072 {
00073 return _Tab[i].name;
00074 }
00075 }
00076 return NULL;
00077 }
00078
00079 ScbLineStyle scb_line_style_from_str(const char * str)
00080 {
00081 int i;
00082 for(i = 0; i < LineTabSize; ++i)
00083 {
00084 if (0 == strcasecmp(str, _Tab[i].name))
00085 {
00086 return _Tab[i].style;
00087 }
00088 }
00089 return SCB_LINE_INVALID;
00090 }
00091
00092
00093
00094
00095
00096
00097 ScbStrokePtr scb_stroke_new()
00098 {
00099 ScbStrokePtr ptr = g_new0(ScbStroke, 1);
00100 SCB_RET_NULL_IF(NULL == ptr, "Not enough memory for stroke!");
00101
00102
00103 if (!scb_points_new(&ptr->points, SCB_DEF_STROKE_POINTSIZE))
00104 {
00105
00106 g_free(ptr);
00107 return NULL;
00108 }
00109
00110
00111 ptr->style.color = SCB_DEV_COLOR_BLACK;
00112 ptr->style.layer = SCB_DEF_STROKE_LAYER;
00113 ptr->style.lineStyle = SCB_DEF_STROKE_LINESTYLE;
00114 ptr->style.penSize = SCB_DEF_STROKE_PENSIZE;
00115
00116
00117 ptr->rect.left = INT_MAX;
00118 ptr->rect.top = INT_MAX;
00119 ptr->rect.right = INT_MIN;
00120 ptr->rect.bottom = INT_MIN;
00121
00122
00123 scb_fast_draw_reset_context();
00124 return ptr;
00125 }
00126
00127 ScbStrokePtr scb_stroke_new_with_style(ScbStrokeStylePtr pStyle)
00128 {
00129 SCB_RET_NULL_IF(NULL == pStyle, "Invalid pointer!");
00130
00131 ScbStrokePtr ptr = g_new0(ScbStroke, 1);
00132 SCB_RET_NULL_IF(NULL == ptr, "Not enough memory for stroke!");
00133
00134
00135 if (!scb_points_new(&ptr->points, SCB_DEF_STROKE_POINTSIZE))
00136 {
00137
00138 g_free(ptr);
00139 return NULL;
00140 }
00141
00142
00143 ptr->style = *pStyle;
00144
00145
00146 ptr->rect.left = INT_MAX;
00147 ptr->rect.top = INT_MAX;
00148 ptr->rect.right = INT_MIN;
00149 ptr->rect.bottom = INT_MIN;
00150
00151
00152 scb_fast_draw_reset_context();
00153 return ptr;
00154 }
00155
00156
00157
00158 void scb_stroke_free(ScbStrokePtr stroke)
00159 {
00160 SCB_RET_IF(NULL == stroke, "Attempt to release NULL pointer!");
00161 if (stroke->points.points)
00162 {
00163 scb_points_free(&stroke->points);
00164 }
00165 g_free(stroke);
00166 }
00167
00168
00169
00170 int scb_stroke_add_point(ScbStrokePtr stroke, ScbDevPointPtr point)
00171 {
00172 SCB_RET_INT_IF(NULL == stroke, SCB_RET_ERR, "stroke pointer is NULL!");
00173 SCB_RET_INT_IF(NULL == point, SCB_RET_ERR, "Invalid point pointer!");
00174
00175
00176
00177 #if (SCB_DEBUG_ON)
00178
00179
00180
00181
00182 #endif
00183
00184 scb_points_append(&stroke->points, point);
00185
00186
00187 if (stroke->rect.left > point->x)
00188 {
00189 stroke->rect.left = point->x;
00190 }
00191 if (stroke->rect.right < point->x)
00192 {
00193 stroke->rect.right = point->x;
00194 }
00195
00196 if (stroke->rect.top > point->y)
00197 {
00198 stroke->rect.top = point->y;
00199 }
00200 if (stroke->rect.bottom < point->y)
00201 {
00202 stroke->rect.bottom = point->y;
00203 }
00204 return SCB_RET_OK;
00205 }
00206
00207
00208 int scb_stroke_get_point_count(ScbStrokePtr stroke)
00209 {
00210 SCB_RET_INT_IF(NULL == stroke || NULL == stroke->points.points, SCB_INVALID_COUNT, "Invalid pointer(s)!");
00211 return stroke->points.points->len;
00212 }
00213
00214
00215
00216 ScbPointPtr scb_stroke_get_point_data(ScbStrokePtr stroke)
00217 {
00218 SCB_RET_NULL_IF(NULL == stroke, "Invalid pointer!");
00219 return scb_points_get_data(&stroke->points);
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255 void scb_stroke_fast_draw_point(ScbStrokePtr stroke, ScbDevPointPtr point)
00256 {
00257 SCB_RET_IF(NULL == stroke || NULL == point, "NULL storke or point!");
00258
00259 if (scb_fast_draw_now())
00260 {
00261
00262 scb_fast_draw();
00263
00264
00265 scb_fast_draw_reset_context();
00266 }
00267
00268
00269 scb_fast_draw_record(point,
00270 stroke->style.penSize,
00271 stroke->style.color,
00272 TRUE);
00273 }
00274
00275
00276
00277
00278
00279 void scb_stroke_fast_draw_point_done(ScbStrokePtr stroke, ScbDevPointPtr point)
00280 {
00281 SCB_RET_IF(NULL == stroke || NULL == point, "NULL storke or point!");
00282
00283
00284 scb_fast_draw_record(point,
00285 stroke->style.penSize,
00286 stroke->style.color,
00287 FALSE);
00288
00289
00290 scb_fast_draw();
00291
00292
00293 scb_fast_draw_reset_context();
00294 }
00295
00296
00297
00298
00299 void scb_stroke_fast_draw(ScbStrokePtr stroke)
00300 {
00301 SCB_RET_IF(NULL == stroke || NULL == stroke->points.points, "NULL pointer!");
00302
00303
00304 DrvPointsBuf tmp;
00305 gboolean end_of_stroke;
00306 int i = 0;
00307 int len = stroke->points.points->len;
00308 ScbPointPtr pt = (ScbPointPtr)stroke->points.points->data;
00309
00310
00311 if (len < 0) return;
00312
00313
00314 tmp.count = 0;
00315
00316
00317 end_of_stroke = FALSE;
00318 for(i = 0; i < len; ++i, ++pt)
00319 {
00320
00321 if ( pt->x >= SCB_DEF_BOUNDARY_LEFT && pt->x <= SCB_DEF_BOUNDARY_RIGHT
00322 && pt->y >= SCB_DEF_BOUNDARY_TOP && pt->y <= SCB_DEF_BOUNDARY_BOTTOM )
00323 {
00324
00325 tmp.points[tmp.count].x = pt->x;
00326 tmp.points[tmp.count].y = pt->y;
00327 tmp.points[tmp.count].size = stroke->style.penSize;
00328 tmp.points[tmp.count].pen_down = TRUE;
00329 tmp.points[tmp.count].color = stroke->style.color;
00330 ++tmp.count;
00331 if ( i >= len - 1
00332 || tmp.count >= SCB_DEF_FAST_DRAW_BUF_LEN)
00333 {
00334 end_of_stroke = TRUE;
00335 }
00336 }
00337 else
00338 {
00339
00340 if (tmp.count > 0)
00341 {
00342 end_of_stroke = TRUE;
00343 }
00344 }
00345
00346
00347 if (end_of_stroke)
00348 {
00349
00350 tmp.points[tmp.count - 1].pen_down = FALSE;
00351 scb_driver_draw(&tmp);
00352 tmp.count = 0;
00353 end_of_stroke = FALSE;
00354 }
00355 }
00356 }
00357
00358
00359
00360
00361
00362 gboolean scb_stroke_point_hit_test(ScbStrokePtr stroke,
00363 ScbDevPointPtr point,
00364 const ScbHitTestCtxPtr ctx)
00365 {
00366 SCB_RET_FALSE_IF(NULL == stroke || NULL == point || NULL == ctx,
00367 "Invalid pointer(s)!");
00368
00369
00370 ScbRect tmp;
00371 double ratio = 1.0;
00372 if (fabs(stroke->style.zoom - ctx->zoom) >= e)
00373 {
00374 ratio = stroke->style.zoom / ctx->zoom;
00375 }
00376 tmp.left = point->x * ratio - ctx->size;
00377 tmp.right = point->x * ratio + ctx->size;
00378 tmp.top = point->y * ratio - ctx->size;
00379 tmp.bottom = point->y * ratio + ctx->size;
00380 if (!scb_is_rect_intersect(&stroke->rect, &tmp))
00381 {
00382 return FALSE;
00383 }
00384
00385
00386 ScbRect src;
00387 int size = stroke->style.penSize;
00388 int len = stroke->points.points->len;
00389 ScbPointPtr pts = (ScbPointPtr)stroke->points.points->data;
00390 while (len)
00391 {
00392 src.left = pts->x - size;
00393 src.right = pts->x + size;
00394 src.top = pts->y - size;
00395 src.bottom = pts->y + size;
00396 if (scb_is_rect_intersect(&src, &tmp))
00397 {
00398 #if (SCB_DEBUG_ON)
00399 SCB_TRACE("\nrect1: (%d %d %d %d)\nrect2: (%d %d %d %d)",
00400 src.left, src.top, src.right, src.bottom,
00401 tmp.left, tmp.top, tmp.right, tmp.bottom);
00402 #endif
00403 return TRUE;
00404 }
00405 ++pts; --len;
00406 }
00407 return FALSE;
00408 }
00409
00410
00411
00412
00413 gboolean scb_stroke_line_hit_test(ScbStrokePtr stroke,
00414 ScbDevPointPtr point1,
00415 ScbDevPointPtr point2,
00416 const ScbHitTestCtxPtr ctx)
00417 {
00418 SCB_RET_FALSE_IF(NULL == stroke || NULL == point1 || NULL == point2 || NULL == ctx,
00419 "Invalid pointer(s)!");
00420
00421
00422 ScbRect tmp;
00423 double ratio = 1.0;
00424 ScbDevPoint p1, p2;
00425 if (fabs(stroke->style.zoom - ctx->zoom) >= e)
00426 {
00427 ratio = stroke->style.zoom / ctx->zoom;
00428 p1.x = (int)point1->x * ratio; p1.y = (int)point1->y * ratio;
00429 p2.x = (int)point2->x * ratio; p2.y = (int)point2->y * ratio;
00430 }
00431 else
00432 {
00433 p1 = *point1; p2 = *point2;
00434 }
00435
00436
00437 tmp.left = MIN(p1.x, p2.x) - ctx->size;
00438 tmp.right = MAX(p1.x, p2.x) + ctx->size;
00439 tmp.top = MIN(p1.y, p2.y) - ctx->size;
00440 tmp.bottom = MAX(p1.y, p2.y) + ctx->size;
00441 if (!scb_is_rect_intersect(&stroke->rect, &tmp))
00442 {
00443 return FALSE;
00444 }
00445
00446
00447 int len = stroke->points.points->len;
00448 ScbPointPtr begin = (ScbPointPtr)stroke->points.points->data;
00449 ScbPointPtr end = begin;
00450
00451
00452 if (len == 1)
00453 {
00454 if (scb_is_lines_intersect((ScbPointPtr)&p1, (ScbPointPtr)&p2, begin, end))
00455 {
00456 #if (SCB_DEBUG_ON)
00457 SCB_TRACE("one point hit!");
00458 SCB_TRACE("line in stroke: (%d %d) - (%d %d)",
00459 begin->x, begin->y, end->x, end->y);
00460 SCB_TRACE("user line: (%d %d) - (%d %d)",
00461 p1.x, p1.y, p2.x, p2.y);
00462 #endif
00463 return TRUE;
00464 }
00465 return FALSE;
00466 }
00467
00468
00469 while (len > 1)
00470 {
00471 ++end;
00472 if (scb_is_lines_intersect((ScbPointPtr)&p1, (ScbPointPtr)&p2, begin, end))
00473 {
00474
00475 #if (SCB_DEBUG_ON)
00476 SCB_TRACE("line in stroke: (%d %d) - (%d %d)",
00477 begin->x, begin->y, end->x, end->y);
00478 SCB_TRACE("user line: (%d %d) - (%d %d)",
00479 p1.x, p1.y, p2.x, p2.y);
00480 #endif
00481 return TRUE;
00482 }
00483 begin = end; --len;
00484 }
00485 return FALSE;
00486 }
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496 gboolean scb_stroke_save(ScbStrokePtr stroke, ScbXmlPtr ptr)
00497 {
00498
00499 char xPath[SCB_MAX_XML_PATH] = {0};
00500 strncpy(xPath, ptr->xPath, SCB_MAX_XML_PATH);
00501 strncat(xPath, "/stroke", SCB_MAX_XML_PATH);
00502 snprintf(xPath, SCB_MAX_XML_PATH, "%s/stroke[%d]", ptr->xPath, ptr->index);
00503
00504
00505
00506 const int LINE_BYTES = 33;
00507 int count = scb_stroke_get_point_count(stroke);
00508 if (count)
00509 {
00510 int len = LINE_BYTES * count;
00511 char *buf = g_new0(char, len);
00512 if (NULL == buf) return FALSE;
00513 char *tmp = buf;
00514 ScbPointPtr point = (ScbPointPtr)stroke->points.points->data;
00515 int* ppressure = (int *)stroke->points.pressures->data;
00516
00517 while (count > 0)
00518 {
00519 tmp += snprintf(tmp, LINE_BYTES, "%d %d %d\n",
00520 point->x, point->y, *ppressure);
00521 --count; ++point; ++ppressure;
00522 }
00523 ermXmlNewString(&ptr->handle, ptr->xPath, "stroke", buf);
00524 g_free(buf);
00525 }
00526
00527
00528 ermXmlSetAttributeString(&ptr->handle, xPath, "color",
00529 scb_dev_color_to_html_color(stroke->style.color), SCB_MAX_COLOR_LEN);
00530 ermXmlSetAttributeInt(&ptr->handle, xPath, "layer", stroke->style.layer);
00531 ermXmlSetAttributeInt(&ptr->handle, xPath, "penSize", stroke->style.penSize);
00532 ermXmlSetAttributeString(&ptr->handle, xPath, "linestyle",
00533 scb_line_style_to_str(stroke->style.lineStyle), SCB_MAX_XML_PATH);
00534
00535 char tmp[20] = {0}; snprintf(tmp, 20, "%lf", stroke->style.zoom);
00536 ermXmlSetAttributeString(&ptr->handle, xPath, "zoom",
00537 tmp, SCB_MAX_XML_PATH);
00538
00539 return TRUE;
00540 }
00541
00542
00543
00544
00545 gboolean scb_stroke_load(ScbStrokePtr stroke, ScbXmlPtr ptr)
00546 {
00547
00548 SCB_RET_FALSE_IF(NULL == stroke || NULL == ptr, "Invalid pointer!");
00549
00550
00551 char xPath[SCB_MAX_XML_PATH] = {0};
00552 strncpy(xPath, ptr->xPath, SCB_MAX_XML_PATH);
00553 char * addr = xPath + strnlen(xPath, SCB_MAX_XML_PATH);
00554 snprintf(addr, SCB_MAX_XML_PATH, "/stroke[%d]", ptr->index);
00555
00556
00557
00558 const int MAX_BUF_LEN = SCB_MAX_XML_PATH;
00559 char buf[SCB_MAX_XML_PATH] = {0};
00560 ermXmlGetAttributeString(&ptr->handle, xPath, "color", buf, MAX_BUF_LEN);
00561 stroke->style.color = scb_html_color_to_dev_color(buf, MAX_BUF_LEN);
00562 ermXmlGetAttributeInt(&ptr->handle, xPath, "layer", &stroke->style.layer);
00563 ermXmlGetAttributeInt(&ptr->handle, xPath, "penSize", (int *)&stroke->style.penSize);
00564 ermXmlGetAttributeString(&ptr->handle, xPath, "linestyle", buf, MAX_BUF_LEN);
00565 stroke->style.lineStyle = scb_line_style_from_str(buf);
00566 ermXmlGetAttributeString(&ptr->handle, xPath, "zoom", buf, MAX_BUF_LEN);
00567 sscanf(buf, "%lf", &stroke->style.zoom);
00568
00569
00570 int len = 0;
00571 const char *data = ermXmlGetStringBuffer(&ptr->handle, xPath, &len);
00572 addr = (char *)data;
00573 if (len <= 0 || NULL == data)
00574 {
00575 #if (SCB_DEBUG_ON)
00576
00577
00578 #endif
00579 return FALSE;
00580 }
00581
00582
00583 ScbDevPoint point;
00584 while (data && 0 != *data)
00585 {
00586 if (3 != sscanf(data, "%d %d %d", &point.x, &point.y, &point.pressure))
00587 {
00588 break;
00589 }
00590
00591 scb_stroke_add_point(stroke, &point);
00592 data = strchr(data, '\n');
00593 if (NULL == data)
00594 {
00595 SCB_ERROR("Could not find new line!");
00596 ermXmlFreeStringBuffer(addr);
00597 return FALSE;
00598 }
00599 ++data;
00600 }
00601 ermXmlFreeStringBuffer(addr);
00602 return TRUE;
00603 }
00604
00605 void scb_stroke_set_color(ScbStrokePtr stroke, const ScbDevColor color)
00606 {
00607 SCB_RET_IF(NULL == stroke, "Invalid pointer!");
00608 stroke->style.color = color;
00609 }
00610
00611
00612 ScbDevColor scb_stroke_get_color(ScbStrokePtr stroke)
00613 {
00614 if (NULL == stroke)
00615 {
00616 return SCB_DEV_COLOR_UNKNOWN;
00617 }
00618 return stroke->style.color;
00619 }
00620
00621
00622
00623
00624 void scb_stroke_dump(ScbStrokePtr ptr)
00625 {
00626 SCB_RET_IF(NULL == ptr || NULL == ptr->points.points, "");
00627
00628 int count = ptr->points.points->len;
00629 ScbPointPtr p = (ScbPointPtr)ptr->points.points->data;
00630 int *pp = (int *)ptr->points.pressures->data;
00631 while(count > 0)
00632 {
00633 SCB_DUMP("\t(%d,\t%d,\t%d)", p->x, p->y, *pp);
00634 --count; ++ p; ++pp;
00635 }
00636 }