00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include <stdlib.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <gtk/gtk.h>
00038
00039
00040 #include <limits.h>
00041
00042 #include "ink_intersect.h"
00043 #include "ScribbleLog.h"
00044
00045 #define min(a,b) (((a)<(b))?(a):(b))
00046 #define max(a,b) (((a)>(b))?(a):(b))
00047
00048
00049
00050
00051 #define TOLERANCE_PIXELS -3
00052 #define LONELY_STROKE_POINTS 4
00053
00054
00055
00056 int isPointOutOfRange(int x,int y,int x1,int y1,int x2,int y2)
00057 {
00058 return ( x < x1 || x>x2 || y<y1 || y>y2);
00059 }
00060
00061 int isPointOutOfStroke(PtrStroke pStroke,GdkPoint *p)
00062 {
00063 return isPointOutOfRange(p->x,p->y,
00064 pStroke->min_x,pStroke->min_y,
00065 pStroke->max_x,pStroke->max_y );
00066 }
00067
00068
00069
00070 gboolean isLineCrossStrokeRange(PtrStroke pStroke,GdkPoint *p0,GdkPoint *p1,
00071 int* p_rec_width,int* p_rect_height)
00072 {
00073 if( NULL==p_rec_width || NULL==p_rect_height) return FALSE;
00074
00075 int dest_x,dest_y;
00076 dest_x = max (min(p0->x,p1->x), pStroke->min_x);
00077 dest_y = max (min(p0->y,p1->y), pStroke->min_y);
00078 *p_rec_width = min (max(p0->x,p1->x), pStroke->max_x)- dest_x;
00079 *p_rect_height = min (max(p0->y,p1->y), pStroke->max_y) - dest_y;
00080
00081 return ( *p_rec_width>=0 && *p_rect_height>=0);
00082 }
00083
00084
00085
00086 int lineIntersects(int x1, int y1, int x2, int y2,
00087 int x3, int y3, int x4, int y4)
00088 {
00089 long ry1, ry2, ry3, ry4;
00090 long rx1, rx2, rx4;
00091
00092 if ( (min(x1,x2) > max(x3,x4)) || (min(x3,x4) > max(x1,x2)) )
00093 {
00094 return 0;
00095 }
00096
00097 if ( (min(y1,y2) > max(y3,y4)) || (min(y3,y4) > max(y1,y2)) )
00098 {
00099 return 0;
00100 }
00101
00102 x2 -= x1; y2 -= y1;
00103 x3 -= x1; y3 -= y1;
00104 x4 -= x1; y4 -= y1;
00105
00106 ry3 = (long) y3 * x2 - (long) x3 * y2;
00107 ry4 = (long) y4 * x2 - (long) x4 * y2;
00108
00109 if((ry3 > 0 && ry4 > 0) || (ry3 < 0 && ry4 < 0))
00110 return (0);
00111
00112 x1 = -x3; y1 = -y3;
00113 x2 -= x3; y2 -= y3;
00114 x4 -= x3; y4 -= y3;
00115
00116 ry1 = (long) y1 * x4 - (long) x1 * y4;
00117 ry2 = (long) y2 * x4 - (long) x2 * y4;
00118
00119 if((ry1 > 0 && ry2 > 0) || (ry1 < 0 && ry2 < 0))
00120 return 0;
00121
00122 if(ry1 || ry2 || ry3 || ry4)
00123 return 1;
00124
00125
00126 if(x4 == 0 && y4 == 0)
00127 {
00128 if((x1 > 0 && x2 > 0) || (x1 < 0 && x2 < 0)) return 0;
00129 if(x1 == 0 && x2 == 0)
00130 {
00131 if ((y1 > 0 && y2) > 0 || (y1 < 0 && y2 < 0)) return 0;
00132 }
00133 return 1;
00134 }
00135
00136 rx1 = (long) x1 * x4 + (long) y1 * y4;
00137 rx2 = (long) x2 * x4 + (long) y2 * y4;
00138 rx4 = (long) x4 * x4 + (long) y4 * y4;
00139
00140 if(rx1 >= 0 && rx1 <= rx4) return 1;
00141
00142 if(rx2 >= 0 && rx2 <= rx4) return 1;
00143
00144 if(rx1 <= rx2)
00145 {
00146 if(0 >= rx1 && 0 <= rx2) return 1;
00147 if(rx4 >= rx1 && rx4 <= rx2) return 1;
00148 }
00149 else
00150 {
00151 if(0 >= rx2 && 0 <= rx1) return 1;
00152 if(rx4 >= rx2 && rx4 <= rx1) return 1;
00153 }
00154 return 0;
00155 }
00156
00157
00158 int isIntersects(PtrStroke pStroke, GdkPoint *srcPt1, GdkPoint *srcPt2)
00159 {
00160 InkPoint *targetPt1, *targetPt2;
00161 int i;
00162
00163 if ((srcPt1->x == srcPt2->x) && (srcPt1->y == srcPt2->y))
00164 {
00165 return 0;
00166 }
00167
00168 targetPt1 = pStroke->firstPoint;
00169
00170 for (i=1; i < pStroke->nPoints; i++)
00171 {
00172 targetPt2 = targetPt1->nextPoint;
00173 if ( (targetPt1->x != targetPt2->x)
00174 ||(targetPt1->y != targetPt2->y) )
00175 {
00176 if (lineIntersects(srcPt1->x - pStroke->iPenSize/2,
00177 srcPt1->y - pStroke->iPenSize/2,
00178 srcPt2->x + pStroke->iPenSize/2,
00179 srcPt2->y + pStroke->iPenSize/2,
00180 targetPt1->x,
00181 targetPt1->y,
00182 targetPt2->x,
00183 targetPt2->y) > 0)
00184 {
00185 return 1;
00186 break;
00187 }
00188 }
00189
00190 targetPt1 = targetPt2;
00191 }
00192 return 0;
00193 }
00194
00195
00196 #define ERASER_SIZE 8
00197 int hitTest(PtrStroke pStroke, GdkPoint *point)
00198 {
00199 PtrInkPoint pt;
00200 int i;
00201
00202 pt = pStroke->firstPoint;
00203
00204 int iEraserSize=ERASER_SIZE;
00205 for (i=0; i < pStroke->nPoints; i++)
00206 {
00207 if ( ( pt->x >= (point->x - iEraserSize/2))
00208 && ( pt->x <= (point->x + iEraserSize/2))
00209 && ( pt->y >= (point->y - iEraserSize/2))
00210 && ( pt->y <= (point->y + iEraserSize/2)) )
00211 {
00212 return 1;
00213 }
00214 pt = pt->nextPoint;
00215 }
00216 return 0;
00217 }
00218
00219
00220 PtrStrokeIntersections_t findIntersections(PtrStroke pStroke, GdkPoint *srcPt1, GdkPoint *srcPt2)
00221 {
00222 InkPoint *targetPt1, *targetPt2;
00223 int i;
00224 PtrStrokeIntersections_t intersections = NULL;
00225 StrokeIntersection_t *pSection;
00226 StrokeIntersection_t *pCurSection = NULL;;
00227
00228 if ( (srcPt1->x == srcPt2->x) && (srcPt1->y == srcPt2->y) )
00229 {
00230 return NULL;
00231 }
00232
00233
00234 intersections = (PtrStrokeIntersections_t)
00235 malloc(sizeof(StrokeIntersections_t));
00236
00237 memset(intersections, 0, sizeof(StrokeIntersections_t));
00238
00239 targetPt1 = pStroke->firstPoint;
00240 for (i=1; i < pStroke->nPoints; i++)
00241 {
00242 targetPt2 = targetPt1->nextPoint;
00243 if ( (targetPt1->x != targetPt2->x)
00244 ||(targetPt1->y != targetPt2->y) )
00245 {
00246 if (lineIntersects(srcPt1->x - pStroke->iPenSize/2,
00247 srcPt1->y - pStroke->iPenSize/2,
00248 srcPt2->x + pStroke->iPenSize/2,
00249 srcPt2->y + pStroke->iPenSize/2,
00250 targetPt1->x,
00251 targetPt1->y,
00252 targetPt2->x,
00253 targetPt2->y) > 0)
00254 {
00255 pSection = (StrokeIntersection_t *)
00256 malloc(sizeof(StrokeIntersection_t));
00257
00258 pSection->beginPt = targetPt1;
00259 pSection->endPt = targetPt2;
00260 pSection->pNextSection = NULL;
00261
00262 if (intersections->interSection == NULL)
00263 {
00264 pCurSection = intersections->interSection = pSection;
00265 }
00266 else if (pCurSection != NULL)
00267 {
00268 pCurSection->pNextSection = pSection;
00269 }
00270 else
00271 {
00272 SB_INKERRPRINTF("ERROR in Scribble\n");
00273 }
00274 intersections->nSections++;
00275 }
00276 }
00277
00278 targetPt1 = targetPt2;
00279 }
00280 return intersections;
00281 }
00282
00283
00284 void delStroke(PtrInk pink,PtrStroke pPrev,PtrStroke *ppCur,PtrInk pDelInk)
00285 {
00286 if( NULL==pink || NULL==*ppCur) return ;
00287
00288 if( pPrev!=NULL && pPrev->nextStroke!=*ppCur) return ;
00289
00290 PtrStroke pNext=(*ppCur)->nextStroke;
00291
00292 if( NULL==pDelInk->firstStroke)
00293 {
00294 pDelInk->firstStroke=pDelInk->lastStroke=*ppCur;
00295 }
00296 else
00297 {
00298 pDelInk->lastStroke->nextStroke=*ppCur;
00299 pDelInk->lastStroke=*ppCur;
00300 }
00301 pDelInk->nStrokes++;
00302 (*ppCur)->nextStroke=NULL;
00303
00304 pink->nStrokes--;
00305 *ppCur=pNext;
00306 if( NULL==pPrev )
00307 {
00308 pink->firstStroke=pNext;
00309 }
00310 else
00311 {
00312 pPrev->nextStroke=pNext;
00313 }
00314 if( NULL==pNext)
00315 {
00316 pink->lastStroke=pPrev;
00317 }
00318 SB_INKPRINTF("removed!\n");
00319 }
00320
00321
00322
00323 void delStrokesByLine(PtrInk pink,GdkPoint *p0,GdkPoint *p1,PtrInk pDelInk)
00324 {
00325 int i;
00326
00327 if( NULL==pink || NULL==pDelInk) return;
00328
00329 PtrStroke pCurStroke = pink->firstStroke;
00330 PtrStroke pPrevStroke = NULL;
00331
00332 gboolean bRealIntersect,bCrossStrokeRange;
00333 int rect_w,rect_h;
00334
00335 int nStrokes=pink->nStrokes;
00336 for (i=0; i< nStrokes ;i++)
00337 {
00338 if ( NULL==pCurStroke ) break;
00339
00340
00341
00342 bCrossStrokeRange=isLineCrossStrokeRange(pCurStroke,p0,p1,&rect_w,&rect_h);
00343 bRealIntersect=FALSE;
00344 if( pCurStroke->nPoints <= LONELY_STROKE_POINTS )
00345 {
00346 if( rect_w>=TOLERANCE_PIXELS && rect_h>=TOLERANCE_PIXELS )
00347 {
00348 SB_INKPRINTF("\n__special:p0=[%d,%d],p1=[%d,%d],[rect_w=%d,rect_h=%d]\n",
00349 p0->x,p0->y,p1->x,p1->y,rect_w,rect_h);
00350
00351
00352 if( hitTest(pCurStroke, p0) || hitTest(pCurStroke, p1))
00353 {
00354 bRealIntersect=TRUE;
00355 }
00356 SB_INKPRINTF("hitTest: bRealIntersect=%d\n",bRealIntersect);
00357 }
00358 }
00359 if( !bRealIntersect && bCrossStrokeRange)
00360 {
00361 if( isIntersects(pCurStroke,p0,p1) )
00362 {
00363 bRealIntersect=TRUE;
00364 }
00365 SB_INKPRINTF("isIntersects: bRealIntersect=%d\n",bRealIntersect);
00366 }
00367 if(bRealIntersect)
00368 {
00369 SB_INKPRINTF("\n(%d,%d),(%d,%d)intersect,range[(%d,%d),(%d,%d)]\n",
00370 p0->x,p0->y,p1->x,p1->y,
00371 pCurStroke->min_x,pCurStroke->min_y,
00372 pCurStroke->max_x,pCurStroke->max_y );
00373
00374 delStroke(pink,pPrevStroke,&pCurStroke,pDelInk);
00375 continue;
00376 }
00377
00378 pPrevStroke=pCurStroke;
00379 pCurStroke = pCurStroke->nextStroke;
00380 }
00381 }
00382
00383
00384
00385 void delInterSectLines(PtrInk pink,GdkPoint *p0,GdkPoint *p1)
00386 {
00387 PtrStrokeIntersections_t intersections;
00388 int i,j;
00389 StrokeIntersection_t *pCurIntersection=NULL;
00390
00391 PtrStroke pCurStroke = pink->firstStroke;
00392 int nStrokes=pink->nStrokes;
00393 for (i=0; i<nStrokes ;i++,pCurStroke = pCurStroke->nextStroke)
00394 {
00395 if ( NULL==pCurStroke ) break;
00396
00397 intersections = findIntersections(pCurStroke,p0,p1);
00398
00399 if ( NULL==intersections ) continue;
00400
00401 pCurIntersection = intersections->interSection;
00402
00403 for (j=0; j<intersections->nSections;i++)
00404 {
00405 if ( NULL==pCurIntersection ) break;
00406
00407
00408
00409
00410
00411
00412
00413
00414 pCurIntersection = pCurIntersection->pNextSection;
00415 }
00416 }
00417 }
00418