#include <tracergn.h>
Inheritance diagram for TraceRegion:
Public Member Functions | |
TraceRegion () | |
Sets intial values up. | |
~TraceRegion () | |
Destructs object. | |
BOOL | UseBitmap (KernelBitmap *pBitmap) |
Points the TraceRegion at a particular bitmap and claims the relevant size buffers. | |
BOOL | UsePath (Path *pPath) |
Specifies we should use a particular path. The path is initialised, cleared etc. | |
BOOL | Trace (INT32 InitialX, INT32 InitialY, BfxPixelOp *thepBfxPixelOp) |
Does a single boundary trace. | |
BOOL | SetParams (double *pPixelError=NULL) |
Sets the tracing parameters. | |
BOOL | GetParams (double *pPixelError=NULL) |
Sets the tracing parameters. | |
Static Public Member Functions | |
static void | Test (UndoableOperation *Op) |
Internal test routine. | |
Protected Member Functions | |
BOOL | TraceBoundary (DocCoord Origin, DocCoord Point1, DocCoord Point2) |
Does a single boundary trace. | |
BOOL | FillBoundaryBuffer (BOOL *End) |
Fills up the boundary buffer. | |
BOOL | ProcessBoundaryBuffer (BOOL Done=FALSE) |
Empties the boundary buffer. | |
BOOL | FindInitialPoint (BOOL *End) |
Finds an initial point to start at. | |
void | FitCubic (INT32 FirstPoint, INT32 LastPoint, TraceBoundaryPoint Tangent1, TraceBoundaryPoint Tangent2, BOOL IsStartCusp, BOOL IsEndCusp) |
This function is recursive. It tries to fit a cubic function to the coordinates in the path between FirstPoint and LastPoint. It then compares this function with the actual coordinates to determine how good a fit it has found. If the fit is good it is added to the path object. If the fit is bad then it is split at the point where the fit is at its worst and FitCubic is called again for the left and right halves. Scope: private. | |
void | GenerateBezier (INT32 FirstPoint, INT32 LastPoint, TraceBoundaryPoint Tangent1, TraceBoundaryPoint Tangent2, TraceBoundaryPoint *Bezier) |
This function supplies the maths to try and fit a cubic function to a set of points. It spends its time trying to come up with good lengths for the two tangents passed in to maximise the closeness of the fit. If it fails to come up with realistic results it simply sets the tangent lengths to be 1/3 of the distance between the start point and the end point. Scope: private. | |
TraceBoundaryPoint | BezierPoint (TraceBoundaryPoint *Bez, double u) |
This function simply evaluates the bezier function for a given position and is used to help when determining how good a fit we have obtained Scope: private. | |
BOOL | CalcMaxError (INT32 LeftPoint, INT32 RightPoint, TraceBoundaryPoint *Bezier, INT32 *SplitPoint, double *MaxDist, INT32 Level) |
Finds out how good a fit the bezier curve we have created is when compared with the data points Scope: private. | |
void | Parameterize (INT32 FirstPoint, INT32 LastPoint) |
This function determines the TPoints which will be fitted (i.e. the trace boundary points we use) and the TValues which will be assigned to them (i.e. the t values along the chord length to which the points correspond). Scope: private. | |
TraceBoundaryPoint | LeftTangent (INT32 Start, INT32 Points) |
Finds the Left tangent at the given point in the path Scope: private. | |
TraceBoundaryPoint | RightTangent (INT32 End, INT32 Points) |
Finds the Right tangent at the given point in the path Scope: private. | |
TraceBoundaryPoint | CentreTangent (INT32 Centre, INT32 Points) |
Finds the tangent at the centre of the path Scope: private. | |
void | InsertBezier (TraceBoundaryPoint *Bezier, BOOL IsStartCusp, BOOL IsEndCusp) |
Adds the bezier curve to the path. If it is that last curve in the fitting (ie Depth is 0) then the rotate flag will not be set Scope: private. | |
void | InsertLine (const DocCoord &Start, const DocCoord &End, BOOL IsStartCusp, BOOL IsEndCusp) |
Inserts a straight curve into the path. It keeps it as a curve so that the path will continue to look smooth after it is edited. If this is the last Path element in the fit, (ie Depth is zero) then the rotate flag will not be set. Scope: private. | |
void | InsertStraightLine (const DocCoord &End) |
Inserts a straight Line into the path. This is used in cases where the Line segment must be kept as a straight line (ie by using Straight Line Mode of the FreeHand tool) Scope: private. | |
double | Bezier0 (double u) |
double | Bezier1 (double u) |
double | Bezier2 (double u) |
double | Bezier3 (double u) |
BOOL | IsCuspDirectionChange (INT32 dir1, INT32 dir2) |
Protected Attributes | |
TraceBoundaryPoint * | BoundaryBuffer |
BfxPixelOp * | pBfxPixelOp |
KernelBitmap * | Bitmap |
INT32 | xsize |
INT32 | ysize |
TraceBoundaryPoint | InitialPoint |
TraceBoundaryPoint | HeadPoint |
INT32 | InitialDirection |
INT32 | TailDirection |
INT32 | HeadDirection |
TraceBoundaryPoint | FirstBufferPoint |
INT32 | BoundaryTail |
INT32 | BoundaryHead |
INT32 | BoundaryRingMask |
INT32 | BoundaryRingSize |
double | Error |
double | PixelError |
BOOL | VirginBuffer |
BOOL | VirginPath |
BOOL | AtCusp |
BOOL | TailCusp |
Path * | ThePath |
TraceBoundaryPoint | Directions [(0x7)+1] |
TraceBoundaryPoint | DirectionPoint [(0x7)+1][(0x7)+1][4] |
double | TValues [10+1] |
INT32 | TPoints [10+1] |
TraceBoundaryPoint | Q1 [3] |
TraceBoundaryPoint | Q2 [2] |
INT32 | NumTPoints |
Private Member Functions | |
CC_DECLARE_DYNCREATE (TraceRegion) |
Definition at line 318 of file tracergn.h.
|
Sets intial values up.
Definition at line 165 of file tracergn.cpp. 00166 { 00167 pBfxPixelOp = NULL; 00168 BoundaryBuffer = NULL; 00169 BoundaryRingSize = 0; 00170 BoundaryRingMask =0; 00171 Bitmap = NULL; 00172 xsize = 1; 00173 ysize = 1; 00174 VirginBuffer = TRUE; 00175 AtCusp = FALSE; 00176 TailCusp = FALSE; 00177 TailDirection = -1; 00178 ThePath = NULL; 00179 00180 double TheError = 1.00; 00181 SetParams(&TheError); 00182 00183 /* 00184 In each direction of travel we always leave with a particular corner of the pixel set. In some directinos 00185 of travel, we have to set 2 edges. Here goes: 00186 00187 ->1-X 00188 | | This is how an east going trace is represented. The top edge is the one we need to fill in. 00189 | | 00190 ---- 00191 00192 ->1- 00193 | V This is how a SE going trace is represented. We have 2 edges to fill in this time. 00194 | 2 00195 ---- 00196 00197 When there is a change in direction, things become more complex. Let us assume that the current 00198 direction is east, then note (for the following new directions) how will fill be buffer in: 00199 00200 Current direction East Current direction south east: 00201 00202 ->1-X ->1-X 00203 | | E | | E 00204 | | | | 00205 ---- ---- 00206 00207 ->1- ->1- 00208 | V SE | V SE 00209 | 2 | 2 00210 ----X ----X 00211 00212 ->1-C ->1- 00213 | V S | V S 00214 | 2 | 2 00215 ----X ----X 00216 00217 ->1-C ->1- 00218 | V SW | V SW 00219 | 2 | 2 00220 X-<3- X-<3-C 00221 00222 ->1-C ->1- 00223 | V W | V W 00224 | 2 | 2 00225 X-<3-(C) X-<3-C 00226 00227 X---- ->1- 00228 | | NW (theoretically impossible - no edges) 4 V NW 00229 | | ^ 2 00230 ---- -<3-C 00231 00232 C---- X---- 00233 | | N (no edges (correct place)) | | N (theoretically impossible) 00234 | | | | 00235 ---- ---- 00236 00237 ->1- ->1-X 00238 | | NE | | NE 00239 | | | | 00240 ---- ---- 00241 00242 00243 Note how strikingly similar these are! We use the RH column one as that's generic for both sides. 00244 00245 */ 00246 00247 00248 00249 00250 // Grrr... This should be static but lovely C++ wont let me compile it. Thanks a lot C++ 00251 // Heh what's 128 bytes when you have a bitmap to trace 00252 Directions[0].Init( (1<<8), (0<<8)); // East 00253 Directions[1].Init( (1<<8),-(1<<8)); // South East 00254 Directions[2].Init( (0<<8),-(1<<8)); // South 00255 Directions[3].Init(-(1<<8),-(1<<8)); // South West 00256 Directions[4].Init(-(1<<8), (0<<8)); // West 00257 Directions[5].Init(-(1<<8), (1<<8)); // North West 00258 Directions[6].Init( (0<<8), (1<<8)); // North 00259 Directions[7].Init( (1<<8), (1<<8)); // North East 00260 00261 // First sort out the non-diagonal table 00262 DirectionPoint[0][0][0].Init( (1<<7), (1<<7)); // East to East 00263 DirectionPoint[0][0][1].Init( -1, -1); // No point 2 00264 DirectionPoint[0][0][2].Init( -1, -1); // No point 3 00265 DirectionPoint[0][0][3].Init( -1, -1); // No point 4 00266 00267 DirectionPoint[0][1][0].Init( (1<<7), (1<<7)); // East to SE 00268 DirectionPoint[0][1][1].Init( (1<<7),-(1<<7)); // point 2 00269 DirectionPoint[0][1][2].Init( -1, -1); // No point 3 00270 DirectionPoint[0][1][3].Init( -1, -1); // No point 4 00271 00272 DirectionPoint[0][2][0].Init( (1<<7), (1<<7)); // East to S 00273 DirectionPoint[0][2][1].Init( -1, 2); // No point 2, go south 00274 DirectionPoint[0][2][2].Init( -1, -1); // No point 3 00275 DirectionPoint[0][2][3].Init( -1, -1); // No point 4 00276 00277 DirectionPoint[0][3][0].Init( (1<<7), (1<<7)); // East to SW 00278 DirectionPoint[0][3][1].Init( -1, 3); // No point 2, go SW 00279 DirectionPoint[0][3][2].Init( -1, -1); // point 3 00280 DirectionPoint[0][3][3].Init( -1, -1); // No point 4 00281 00282 DirectionPoint[0][4][0].Init( (1<<7), (1<<7)); // East to W 00283 DirectionPoint[0][4][1].Init( -1, 2); // No point 2, go S 00284 DirectionPoint[0][4][2].Init( -1, -1); // point 3 00285 DirectionPoint[0][4][3].Init( -1, -1); // No point 4 00286 00287 DirectionPoint[0][5][0].Init( (1<<7), (1<<7)); // South East to NW 00288 DirectionPoint[0][5][1].Init( (1<<7),-(1<<7)); // point 2 00289 DirectionPoint[0][5][2].Init( -1, 5); // No point 3, go NW 00290 DirectionPoint[0][5][3].Init( -1, -1); // No point 4 00291 00292 DirectionPoint[0][6][0].Init( -1, 6); // No point 1, go N 00293 DirectionPoint[0][6][1].Init( -1, -1); // No point 2 00294 DirectionPoint[0][6][2].Init( -1, -1); // No point 3 00295 DirectionPoint[0][6][3].Init( -1, -1); // No point 4 00296 00297 DirectionPoint[0][7][0].Init( (1<<7), (1<<7)); // East to NE 00298 DirectionPoint[0][7][1].Init( -1, -1); // No point 2 00299 DirectionPoint[0][7][2].Init( -1, -1); // No point 3 00300 DirectionPoint[0][7][3].Init( -1, -1); // No point 4 00301 00302 00303 00304 DirectionPoint[1][0][0].Init( (1<<7), (1<<7)); // South East to East 00305 DirectionPoint[1][0][1].Init( -1, -1); // No point 2 00306 DirectionPoint[1][0][2].Init( -1, -1); // No point 3 00307 DirectionPoint[1][0][3].Init( -1, -1); // No point 4 00308 00309 DirectionPoint[1][1][0].Init( (1<<7), (1<<7)); // South East to SE 00310 DirectionPoint[1][1][1].Init( (1<<7),-(1<<7)); // point 2 00311 DirectionPoint[1][1][2].Init( -1, -1); // No point 3 00312 DirectionPoint[1][1][3].Init( -1, -1); // No point 4 00313 00314 DirectionPoint[1][2][0].Init( (1<<7), (1<<7)); // South East to S 00315 DirectionPoint[1][2][1].Init( (1<<7),-(1<<7)); // point 2 00316 DirectionPoint[1][2][2].Init( -1, -1); // No point 3 00317 DirectionPoint[1][2][3].Init( -1, -1); // No point 4 00318 00319 DirectionPoint[1][3][0].Init( (1<<7), (1<<7)); // South East to SW 00320 DirectionPoint[1][3][1].Init( (1<<7), (0<<7)); // point 3 00321 DirectionPoint[1][3][2].Init( -1, 3); // No point 4, go SW 00322 DirectionPoint[1][3][3].Init( -1, -1); // No point 4 00323 00324 DirectionPoint[1][4][0].Init( (1<<7), (1<<7)); // South East to W 00325 DirectionPoint[1][4][1].Init( (1<<7),-(1<<7)); // point 2 00326 DirectionPoint[1][4][2].Init( -1, 4); // No point 3, go W 00327 DirectionPoint[1][4][3].Init( -1, -1); // No point 4 00328 00329 DirectionPoint[1][5][0].Init( (1<<7), (1<<7)); // South East to NW 00330 DirectionPoint[1][5][1].Init( (1<<7),-(1<<7)); // point 2 00331 DirectionPoint[1][5][2].Init( -1, 5); // No point 3, go NW 00332 DirectionPoint[1][5][3].Init( -1, -1); // No point 4 00333 00334 DirectionPoint[1][6][0].Init( -1, 6); // No point 1, go N 00335 DirectionPoint[1][6][1].Init( -1, -1); // No point 2 00336 DirectionPoint[1][6][2].Init( -1, -1); // No point 3 00337 DirectionPoint[1][6][3].Init( -1, -1); // No point 4 00338 00339 DirectionPoint[1][7][0].Init( (0<<7), (1<<7)); // South East to NE 00340 DirectionPoint[1][7][1].Init( -1, 7); // No point 2, go NE 00341 DirectionPoint[1][7][2].Init( -1, -1); // No point 3 00342 DirectionPoint[1][7][3].Init( -1, -1); // No point 4 00343 00344 INT32 i; 00345 INT32 j; 00346 INT32 k; 00347 for (i=2; i<=7; i+=1) for (j=0; j<=7; j++) for (k=0; k<=3; k++) 00348 { 00349 // Go from direction i to direction j, i even 00350 INT32 j2 = (j-(i & 0x6)) & TR_NUMDIRECTIONMASK; 00351 DirectionPoint[i][j][k]=DirectionPoint[i & 0x1][j2][k]; 00352 00353 if (DirectionPoint[i][j][k].x != -1) 00354 { 00355 DirectionPoint[i][j][k].RotateDirection(Directions[(i & 0x6)]); 00356 } 00357 else 00358 { 00359 if (DirectionPoint[i][j][k].y != -1) 00360 DirectionPoint[i][j][k].y = (((INT32)(DirectionPoint[(i & 0x1)][j2][k].y) + (i & 0x6)) & TR_NUMDIRECTIONMASK); 00361 } 00362 } 00363 00364 TraceBoundaryPoint Centre; 00365 Centre.Init((1<<7),(1<<7)); 00366 for (i=0; i<=7; i+=1) for (j=0; j<=7; j++) for (k=0; k<=3; k++) 00367 { 00368 if (DirectionPoint[i][j][k].x != -1) 00369 { 00370 DirectionPoint[i][j][k].translate(Centre); 00371 } 00372 } 00373 00374 }
|
|
Destructs object.
Definition at line 505 of file tracergn.cpp. 00506 { 00507 if (BoundaryBuffer) CCFree(BoundaryBuffer); 00508 // Clear some hanging pointers 00509 BoundaryBuffer = NULL; 00510 Bitmap = NULL; 00511 ThePath = NULL; 00512 }
|
|
Definition at line 373 of file tracergn.h.
|
|
Definition at line 374 of file tracergn.h.
|
|
Definition at line 375 of file tracergn.h.
|
|
Definition at line 376 of file tracergn.h.
|
|
This function simply evaluates the bezier function for a given position and is used to help when determining how good a fit we have obtained Scope: private.
Definition at line 1383 of file tracergn.cpp. 01384 { 01385 double OneMinus = 1.0-u; 01386 double uSquared = u*u; 01387 double OneMinusSquared = OneMinus*OneMinus; 01388 01389 TraceBoundaryPoint Coord; 01390 Coord = Bez[0]*(OneMinusSquared*OneMinus); 01391 Coord = Coord + Bez[1]*(3.0*u*OneMinusSquared); 01392 Coord = Coord + Bez[2]*(3.0*uSquared*OneMinus); 01393 Coord = Coord + Bez[3]*(uSquared*u); 01394 01395 return Coord; 01396 }
|
|
Finds out how good a fit the bezier curve we have created is when compared with the data points Scope: private.
Cunningly we move the TValues about if we think they are salvageable. Definition at line 1426 of file tracergn.cpp. 01428 { 01429 TraceBoundaryPoint Q_t, Q1_t, Q2_t; // t evaluated at Q, Q' & Q'' 01430 INT32 MidPoint = (LeftPoint + RightPoint+1)/2; // where we are going to evaluate it 01431 double Distance; 01432 01433 if (!((MidPoint == LeftPoint) || (MidPoint==RightPoint))) 01434 { 01435 01436 for (INT32 iterations=1; iterations<=3; iterations++) 01437 { 01438 double t = TValues[MidPoint]; 01439 TraceBoundaryPoint pt = BoundaryBuffer[TPoints[MidPoint]]; 01440 01441 // Calculate where the curve actually is and find the distance from where we want it 01442 Distance = (BezierPoint(Bezier, t) - pt).SquaredLength(); 01443 01444 if ((Distance > *MaxDist) && (Distance < Error * 2.0)) 01445 // If this is would be the new winner, and it's salvageable (less than twice as far away as we 01446 // we want), recalculate a better TValue 01447 { 01448 01449 // Evaluate Q, Q' & Q'' 01450 double OneMinus = 1.0-t; 01451 double tSquared = t*t; 01452 double OneMinusSquared = OneMinus*OneMinus; 01453 01454 Q_t = Bezier[0] *(OneMinusSquared*OneMinus) + Bezier[1]*(3.0*t*OneMinusSquared) 01455 +Bezier[2] *(3.0*tSquared*OneMinus) + Bezier[3]*(tSquared*t); 01456 Q1_t = Q1[0]*(OneMinusSquared) + Q1[1]*(2.0*t*OneMinus) + Q1[2]*(tSquared); 01457 Q2_t = Q2[0]*(OneMinus) + Q2[1]*(t); 01458 01459 // Now Newton Raphson tprime = t - f(t)/f'(t) 01460 TraceBoundaryPoint QtMinuspt = Q_t - pt; 01461 01462 // changed by Ed Cornes 31/10/95 in an attempt to remove an itermittent floating point exception in the tracer 01463 // t = t - ( (QtMinuspt.x)*(Q1_t.x) + (QtMinuspt.y) * (Q1_t.y) ) / 01464 // ( Q1_t.SquaredLength() + ((QtMinuspt.x) * (Q2_t.x) + (QtMinuspt.y) * (Q2_t.y)) ); 01465 double denom = Q1_t.SquaredLength() + ((QtMinuspt.x) * (Q2_t.x) + (QtMinuspt.y) * (Q2_t.y)); 01466 if (fabs(denom)<1e-50) 01467 denom = (denom<0) ? -1e-50 : 1e-50; 01468 01469 t = t - ( (QtMinuspt.x)*(Q1_t.x) + (QtMinuspt.y) * (Q1_t.y) ) / denom; 01470 if (t<0) t=0; 01471 if (t>1) t=1; 01472 //TRACEUSER( "Alex", _T("Point %f moves to %f\n"),TValues[MidPoint],t); 01473 TValues[MidPoint] = t; 01474 } 01475 else break; // Leave 'for' loop - point OK or point not salvageable 01476 } 01477 01478 if ( Distance >= *MaxDist) 01479 { 01480 *MaxDist = Distance; 01481 *SplitPoint = MidPoint; 01482 } 01483 01484 // If we haven't got a point to split at yet, or if we're in the 4 first points, 01485 // recurse down. This ensures we do 8 points. 01486 if ((*MaxDist<=Error) || (Level<3)) CalcMaxError(LeftPoint, MidPoint, 01487 Bezier, SplitPoint, MaxDist, Level+1); 01488 if ((*MaxDist<=Error) || (Level<3)) CalcMaxError(MidPoint, RightPoint, 01489 Bezier, SplitPoint, MaxDist, Level+1); 01490 01491 } 01492 return(*MaxDist>Error); 01493 }
|
|
|
|
Finds the tangent at the centre of the path Scope: private.
Definition at line 1595 of file tracergn.cpp. 01596 { 01597 TraceBoundaryPoint Left, Right; 01598 TraceBoundaryPoint Tangent(0,0); 01599 01600 Points = 1+MIN (Points/2,MAXTANGENTPOINTS); 01601 if (Points<2) Points=2; 01602 01603 // Make sure that is not of zero length 01604 while ((Tangent.x==0) && (Tangent.y==0)) 01605 { 01606 if ((--Points)>0) 01607 { 01608 // Calc right tangent 01609 Left.x = BoundaryBuffer[Centre-Points].x - BoundaryBuffer[Centre].x; 01610 Left.y = BoundaryBuffer[Centre-Points].y - BoundaryBuffer[Centre].y; 01611 01612 // Calc left tangent 01613 Right.x = BoundaryBuffer[Centre].x - BoundaryBuffer[Centre+Points].x; 01614 Right.y = BoundaryBuffer[Centre].y - BoundaryBuffer[Centre+Points].y; 01615 01616 // Average to get the centre tangent 01617 Tangent.x = (Left.x + Right.x) / 2; 01618 Tangent.y = (Left.y + Right.y) / 2; 01619 01620 } 01621 else 01622 { 01623 ERROR3("Tangent was a zero length vector in the curve fitter (Centre)"); 01624 Tangent.x = -1; 01625 } 01626 } 01627 01628 return Tangent; 01629 }
|
|
Fills up the boundary buffer.
It also stops if it meets a cusp, or the intial point in the initial direction. Definition at line 824 of file tracergn.cpp. 00825 { 00826 INT32 NewDirection; 00827 INT32 Turns; 00828 00829 ERROR2IF((!Bitmap),FALSE,"TraceRegion incorrectly initialised"); 00830 00831 *End=FALSE; 00832 while (BoundaryHead<BoundaryRingSize - 6) // there is enough room in buffer 00833 { 00834 // Calculate the new direction. We start looking at direction-2 but as we add one before we start 00835 // we have -3. If we're at a cusp we know the NewDirection set to HeadDirection is the correct place, 00836 // i.e. we want +0, but because we add one before we start, we want -1. 00837 NewDirection = (HeadDirection-(AtCusp?1:3)) & TR_NUMDIRECTIONMASK; 00838 //NewDirection = (HeadDirection-3) & TR_NUMDIRECTIONMASK; 00839 Turns=0; 00840 TraceBoundaryPoint NewPoint=HeadPoint; // Initialisation unnecessary but quiets the compiler 00841 00842 00843 do 00844 { 00845 // This should only return(TRUE) if asked to trace a 00846 // one pixel shape - else we must have got to this pixel some how. 00847 if ((Turns++)==8) 00848 { 00849 *End=TRUE; 00850 // We want to force it to be the 4 corner case 00851 NewDirection=((HeadDirection & 0x6) + 6) & TR_NUMDIRECTIONMASK; 00852 ERROR3("One pixel regions NYI"); 00853 // The above won't work properly because it's not properly entered. I think we need a horrible 00854 // goto here. 00855 break; 00856 } 00857 // Find next direction 00858 NewDirection = (NewDirection + 1) & TR_NUMDIRECTIONMASK; 00859 NewPoint = HeadPoint; // Calculate the new point 00860 NewPoint.translate(Directions[NewDirection]); 00861 } while (!pBfxPixelOp->IsInRegion(((INT32)(NewPoint.x))>>8, ((INT32)(NewPoint.y))>>8)); 00862 00863 if (VirginBuffer) InitialDirection = TailDirection = NewDirection; 00864 00865 00866 // stick point in ring buffer 00867 // Limit is such that we know we can fit the maximum of 4 points in 00868 INT32 HintPoint=0; 00869 if (!VirginBuffer) 00870 { 00871 if (AtCusp) 00872 { 00873 // Only put the last point in if at a cusp 00874 while ((DirectionPoint[HeadDirection][NewDirection][HintPoint].x != -1) // sufficient check 00875 && (HintPoint<4)) {HintPoint++;} // Don't inc at final point 00876 BoundaryBuffer[BoundaryHead] = HeadPoint; 00877 BoundaryBuffer[BoundaryHead++].translate(DirectionPoint[HeadDirection][NewDirection][HintPoint-1]); 00878 // HintPoint still points at terminator 00879 } 00880 else 00881 { 00882 // Put all points in 00883 while ((DirectionPoint[HeadDirection][NewDirection][HintPoint].x != -1) // sufficient check 00884 && (HintPoint<4)) 00885 { 00886 BoundaryBuffer[BoundaryHead] = HeadPoint; 00887 BoundaryBuffer[BoundaryHead++].translate(DirectionPoint[HeadDirection][NewDirection][HintPoint++]); 00888 } 00889 } 00890 } else while ((DirectionPoint[HeadDirection][NewDirection][HintPoint].x != -1) // sufficient check 00891 && (HintPoint<4)) {HintPoint++;} // Don't inc at final point 00892 00893 00894 if (DirectionPoint[HeadDirection][NewDirection][HintPoint].y !=-1) 00895 { 00896 HeadDirection = (INT32)(DirectionPoint[HeadDirection][NewDirection][HintPoint].y); 00897 // HeadPoint = NewPoint; 00898 AtCusp = TRUE; 00899 if (TailDirection == -1) TailDirection = HeadDirection; 00900 // VirginBuffer = FALSE; 00901 return (TRUE); 00902 } 00903 00904 // check for cusp a with dirty unsigned arithmetic and return NOW if we are there. 00905 // AtCusp = ( ( ((unsigned)(Turns-2)) >=3) && (!AtCusp)); 00906 AtCusp = FALSE; 00907 00908 //if (AtCusp) return (TRUE); // cusp return 00909 00910 00911 if ( (HeadPoint == InitialPoint) && (NewDirection == InitialDirection) && !VirginBuffer ) 00912 { 00913 *End = TRUE; 00914 VirginBuffer = FALSE; 00915 return (TRUE); 00916 } 00917 00918 VirginBuffer = FALSE; 00919 00920 if (TailDirection == -1) TailDirection = NewDirection; 00921 00922 // Set up member vars 00923 HeadPoint = NewPoint; 00924 HeadDirection = NewDirection; 00925 00926 } 00927 00928 return(TRUE); // Out of buffer space, go process some & come back 00929 }
|
|
Finds an initial point to start at.
The boundary buffer is cleared. An initial point will be found if possible and End cleared. If one is not found, End will be set. Definition at line 650 of file tracergn.cpp. 00651 { 00652 INT32 x; 00653 INT32 y; 00654 00655 ERROR2IF((!Bitmap),FALSE,"How about giving us a bitmap first then?"); 00656 00657 InitialDirection = 0; // East 00658 VirginBuffer = TRUE; 00659 BoundaryHead =0; 00660 BoundaryTail =0; 00661 TailDirection = -1; 00662 HeadDirection = 0; 00663 AtCusp=FALSE; 00664 TailCusp = FALSE; 00665 *End = FALSE; 00666 00667 for (y = ysize-1; y>=0; y--) for (x = 0; x < xsize; x++) if (pBfxPixelOp->IsInRegion(x,y)) 00668 { 00669 InitialPoint.x = x<<8; 00670 InitialPoint.y = y<<8; 00671 HeadPoint = InitialPoint; 00672 return (TRUE); 00673 } 00674 00675 *End = TRUE; // Oh dear, no initial point 00676 00677 return(TRUE); 00678 }
|
|
This function is recursive. It tries to fit a cubic function to the coordinates in the path between FirstPoint and LastPoint. It then compares this function with the actual coordinates to determine how good a fit it has found. If the fit is good it is added to the path object. If the fit is bad then it is split at the point where the fit is at its worst and FitCubic is called again for the left and right halves. Scope: private.
Definition at line 1029 of file tracergn.cpp. 01031 { 01032 // Will need space for a Bezier curve 01033 TraceBoundaryPoint Bezier[4]; 01034 TraceBoundaryPoint CentTangent; 01035 INT32 NumPoints = LastPoint - FirstPoint + 1; 01036 INT32 SplitPoint, Split; 01037 01038 01039 // If we have the flexibility, recalculate the tangents to the left and right 01040 if (IsStartCusp) Tangent1 = LeftTangent(FirstPoint, NumPoints); 01041 if (IsEndCusp) Tangent2 = RightTangent(LastPoint, NumPoints); 01042 01043 // The following is actually legal if we start on a cusp 01044 // ERROR3IF(NumPoints<2,"Too few points to fit a cubic"); 01045 if (NumPoints<2) return; 01046 #if 0 01047 // if this segment only has 2 points in it then do the special case 01048 if ( NumPoints == 2 ) 01049 { 01050 InsertLine( DocCoord((INT32)(BoundaryBuffer[FirstPoint].x), (INT32)(BoundaryBuffer[FirstPoint].y)), 01051 DocCoord((INT32)(BoundaryBuffer[LastPoint].x), (INT32)(BoundaryBuffer[FirstPoint].y)), 01052 IsStartCusp, IsEndCusp); 01053 return; 01054 } 01055 #endif 01056 /* Due to a bug in the algorithm we also have to consider 3 points a special case. 01057 01058 Here's what Mathematica reckons is the formula for a bezier A B C D that passes through a point Q 01059 with tangents tx & ty 01060 01061 4 t1x (Ay t2x + Dy t2x - 2 Qy t2x - Ax t2y - Dx t2y + 2 Qx t2y) 01062 {{Bx -> Ax - ---------------------------------------------------------------, 01063 3 (t1y t2x - t1x t2y) 01064 4 t1y (Ay t2x + Dy t2x - 2 Qy t2x - Ax t2y - Dx t2y + 2 Qx t2y) 01065 By -> Ay - ---------------------------------------------------------------, 01066 3 (t1y t2x - t1x t2y) 01067 (12 (Ay + Dy - 2 Qy) t1x - 12 (Ax + Dx - 2 Qx) t1y) t2x 01068 Cx -> Dx - -------------------------------------------------------, 01069 9 (-(t1y t2x) + t1x t2y) 01070 4 (Ay t1x + Dy t1x - 2 Qy t1x - Ax t1y - Dx t1y + 2 Qx t1y) t2y 01071 Cy -> Dy + ---------------------------------------------------------------, 01072 3 (t1y t2x - t1x t2y) 01073 01074 I reckon I can rewrite this better: 01075 01076 01077 F -> (4/3) (A + D - 2 Q) / (t2x t1y - t2y t1x) 01078 01079 B -> Fy t2x - Fx t2y 01080 01081 C -> Fx t1y - Fy t1x 01082 01083 Bx -> Ax - B t1x 01084 01085 By -> Ay - B t1y 01086 01087 Cx -> Dx - C t2x 01088 01089 Cy -> Dy - C t2y 01090 01091 This is all very well and good, but when does it occur? Here's an example: 01092 01093 01094 A B 01095 .... 01096 .... 01097 ...T1 01098 01099 T2....C 01100 01101 01102 Here A is is the FistPoint with tangent T1, and C is the last point with tangent T2. The only bezier that 01103 fits through B as well with tangents specified is a loop that goes left from C, back under it and up through T1. 01104 Though all the maths is fine, and we can even detect this case, it's just not worth it. We just miss out point B. 01105 01106 Oh well, so much for the beaury of mathematics. (PS - the real soln is to introduce 1 or more extra points. But that's 01107 getting silly). 01108 01109 */ 01110 01111 #if 0 01112 // Never appears to run to completion anyway :-( 01113 if (NumPoints == 3) 01114 { 01115 INT32 MidPoint = FirstPoint+1; 01116 double Bottom = 0.75 * (Tangent2.x * Tangent1.y - Tangent2.y * Tangent1.x); 01117 if (Abs(Bottom)>0.001) // Else ignore middle point - this happens if the tangents are nearly parallel 01118 { 01119 TraceBoundaryPoint F = (BoundaryBuffer[FirstPoint]+BoundaryBuffer[LastPoint]-BoundaryBuffer[MidPoint]*2.0)/Bottom; 01120 double B = F.y * Tangent2.x - F.x * Tangent2.y; 01121 double C = F.x * Tangent1.y - F.y * Tangent1.x; 01122 if ((B<0.0) && (C<0.0)) // Not generating a loop 01123 { 01124 Tangent1 = -(Tangent1 * B); 01125 Tangent2 = -(Tangent2 * C); // Don't worry - we just need their directions for the fallback case 01126 // Max distance is ((1<<8)/2)^2 = (1<<14) 01127 if ((Tangent1.SquaredLength()<(1<<14)) && (Tangent2.SquaredLength()<(1<<14))) 01128 { 01129 Bezier[0] = BoundaryBuffer[FirstPoint]; 01130 Bezier[3] = BoundaryBuffer[LastPoint]; 01131 Bezier[1] = BoundaryBuffer[FirstPoint] + Tangent1; 01132 Bezier[2] = BoundaryBuffer[LastPoint] + Tangent2; 01133 InsertBezier(Bezier, IsStartCusp, IsEndCusp); 01134 return; 01135 } 01136 } 01137 } 01138 } 01139 #endif 01140 01141 // We must consider 2 points (or unhandled 3 point cases) as a special case 01142 if ( NumPoints <=2) 01143 { 01144 // With 3 points the distance is always 2. 01145 INT32 Distance = (1<<8)*2/3; 01146 01147 // store the end points 01148 Bezier[0] = BoundaryBuffer[FirstPoint]; 01149 Bezier[3] = BoundaryBuffer[LastPoint]; 01150 01151 // calc the control points 01152 Bezier[1] = Bezier[0] + Tangent1.SetLength(Distance); 01153 Bezier[2] = Bezier[3] + Tangent2.SetLength(Distance); 01154 01155 // add it to the path 01156 InsertBezier(Bezier, IsStartCusp, IsEndCusp); 01157 return; 01158 } 01159 01160 01161 if (NumPoints ==3) 01162 { 01163 Split = FirstPoint + 1; // Midpoint 01164 } 01165 else 01166 { 01167 // Create a Bezier curve from the segemnt and see if it is a good fit 01168 Parameterize(FirstPoint, LastPoint); 01169 01170 GenerateBezier(FirstPoint, LastPoint, Tangent1, Tangent2, Bezier); 01171 01172 SplitPoint=NumTPoints-1; 01173 double MaxError = 0; 01174 if (!CalcMaxError(0, NumTPoints, Bezier, &SplitPoint, &MaxError, 0)) 01175 { 01176 // The mapping was good, so output the curve segment 01177 //TRACEUSER( "Alex", _T(" OK FP=%d, LP=%d, ME=%f\n"),FirstPoint,LastPoint,MaxError); 01178 InsertBezier(Bezier, IsStartCusp, IsEndCusp); 01179 return; 01180 } 01181 01182 Split = TPoints[SplitPoint]; 01183 } 01184 01185 //TRACEUSER( "Alex", _T("Split FP=%d, SP=%d, LP=%d\n"),FirstPoint,Split,LastPoint); 01186 // fitting failed -- split at max error point and fit recursively 01187 CentTangent = CentreTangent(Split, MIN(Split-FirstPoint+1,LastPoint-Split+1)); 01188 //Tangent1=LeftTangent(FirstPoint,SplitPoint-FirstPoint+1); 01189 FitCubic(FirstPoint, Split, Tangent1, CentTangent, IsStartCusp, FALSE); 01190 01191 CentTangent = -CentTangent; 01192 //Tangent2=RightTangent(LastPoint,LastPoint-SplitPoint+1); 01193 FitCubic(Split, LastPoint, CentTangent, Tangent2, FALSE, IsEndCusp); 01194 01195 }
|
|
This function supplies the maths to try and fit a cubic function to a set of points. It spends its time trying to come up with good lengths for the two tangents passed in to maximise the closeness of the fit. If it fails to come up with realistic results it simply sets the tangent lengths to be 1/3 of the distance between the start point and the end point. Scope: private.
Definition at line 1261 of file tracergn.cpp. 01263 { 01264 INT32 pos; 01265 INT32 i; 01266 // INT32 NumPoints = LastPoint - FirstPoint + 1; 01267 01268 // Build a matrix type of thing that contains the tangents scaled by the offsets 01269 TraceBoundaryPoint A[FIT_STEPS+1][2]; // Vector2 (*A)[2] = new Vector2[NumPoints+1][2]; 01270 01271 // Chord length parameterisation 01272 for (pos=0; pos<=NumTPoints; pos++) 01273 { 01274 // Fill the matrix A 01275 A[pos][0] = Tangent1.SetLength( Bezier1(TValues[pos]) ); 01276 A[pos][1] = Tangent2.SetLength( Bezier2(TValues[pos]) ); 01277 } 01278 01279 // For a detailed description of the maths used here, please see Graphics Gems I 01280 // I have made some changes to the basic algorithm used there - the main one is 01281 // that this block of maths is only performed on a small selection of the points 01282 // in the data set, where-as the one in the book uses all the points 01283 double C[2][2]; 01284 double X[2]; 01285 01286 C[0][0] = 0.0; 01287 C[0][1] = 0.0; 01288 C[1][0] = 0.0; 01289 C[1][1] = 0.0; 01290 X[0] = 0.0; 01291 X[1] = 0.0; 01292 01293 TraceBoundaryPoint FirstCoord = BoundaryBuffer[FirstPoint]; 01294 TraceBoundaryPoint LastCoord = BoundaryBuffer[LastPoint]; 01295 TraceBoundaryPoint ThisCoord, Combo; 01296 01297 for (pos=0; pos<=NumTPoints; pos++) 01298 { 01299 C[0][0] += A[pos][0].SquaredLength(); 01300 C[0][1] += A[pos][0].Dot(A[pos][1]); 01301 // Point C[1][0] is the same as C[0][1] and is set outside the loop below 01302 C[1][1] += A[pos][1].SquaredLength(); 01303 01304 // Go ahead and build a vector based on the bezier functions 01305 ThisCoord = BoundaryBuffer[TPoints[pos]]; 01306 Combo = ThisCoord - ((FirstCoord * Bezier0(TValues[pos])) 01307 + (FirstCoord * Bezier1(TValues[pos])) 01308 + (LastCoord * Bezier2(TValues[pos])) 01309 + (LastCoord * Bezier3(TValues[pos]))); 01310 01311 // Combine it with the other points 01312 X[0] += A[pos][0].Dot( Combo ); 01313 X[1] += A[pos][1].Dot( Combo ); 01314 01315 } 01316 01317 // This point in the matrix is the same, so we do not need to do it in the loop 01318 C[1][0] = C[0][1]; 01319 01320 // calc the determinants of C and X 01321 double det_C0_C1 = C[0][0] * C[1][1] - C[1][0] * C[0][1]; 01322 double det_C0_X = C[0][0] * X[1] - C[0][1] * X[0]; 01323 double det_X_C1 = X[0] * C[1][1] - X[1] * C[0][1]; 01324 01325 // finally, derive the length of the ideal tangents 01326 if (det_C0_C1 == 0.0) 01327 det_C0_C1 = (C[0][0] * C[1][1]) * 10e-12; // oh err, whats it up to here then! 01328 01329 double AlphaLeft = det_X_C1 / det_C0_C1; 01330 double AlphaRight = det_C0_X / det_C0_C1; 01331 01332 Bezier[0] = BoundaryBuffer[FirstPoint]; 01333 Bezier[3] = BoundaryBuffer[LastPoint]; 01334 01335 // if alpha negative, the set the tangent length to a third of the distance between 01336 // the start and the end points of the curve segment 01337 if ( AlphaLeft < 0.0 || AlphaRight < 0.0) 01338 { 01339 INT32 Distance = ((LastPoint - FirstPoint)<<8) / 3; 01340 01341 Bezier[1] = Bezier[0] + Tangent1.SetLength(Distance); 01342 Bezier[2] = Bezier[3] + Tangent2.SetLength(Distance); 01343 } 01344 else 01345 { 01346 Bezier[1] = Bezier[0] + Tangent1.SetLength(AlphaLeft); 01347 Bezier[2] = Bezier[3] + Tangent2.SetLength(AlphaRight); 01348 } 01349 01350 // Calculate Q1 (differential) 01351 for (i = 0; i<=2; i++) 01352 { 01353 Q1[i]= (Bezier[i+1]-Bezier[i]) * 3.0; 01354 } 01355 01356 // Calculate Q2 (2nd differential) 01357 for (i = 0; i<=1; i++) 01358 { 01359 Q2[i] = (Q1[i+1]-Q1[i]) * 2.0; 01360 } 01361 01362 }
|
|
Sets the tracing parameters.
Definition at line 419 of file tracergn.cpp. 00420 { 00421 if (pPixelError) *pPixelError = PixelError; 00422 return TRUE; 00423 }
|
|
Adds the bezier curve to the path. If it is that last curve in the fitting (ie Depth is 0) then the rotate flag will not be set Scope: private.
Definition at line 1648 of file tracergn.cpp. 01649 { 01650 // Prepare some flags 01651 PathFlags Flags; 01652 Flags.IsSelected = FALSE; 01653 Flags.IsSmooth = FALSE; 01654 Flags.IsRotate = TRUE; 01655 01656 // Add this Bezier curve into the path 01657 ThePath->InsertCurveTo( DocCoord( (INT32)Bezier[1].x, (INT32)Bezier[1].y), 01658 DocCoord( (INT32)Bezier[2].x, (INT32)Bezier[2].y), 01659 DocCoord( (INT32)Bezier[3].x, (INT32)Bezier[3].y), &Flags); 01660 01661 // Deal with cusps 01662 if (IsStartCusp || IsEndCusp) 01663 { 01664 // Go find out about the path 01665 PathFlags* AllFlags = ThePath->GetFlagArray(); 01666 INT32 NumCoords = ThePath->GetNumCoords(); 01667 01668 if (IsStartCusp) 01669 { 01670 // Patch up the flags of the bits near that start 01671 AllFlags[NumCoords-3].IsRotate = FALSE; 01672 } 01673 01674 if (IsEndCusp) 01675 { 01676 // Patch up the flags of the bits near that end 01677 AllFlags[NumCoords-2].IsRotate = FALSE; 01678 AllFlags[NumCoords-1].IsRotate = FALSE; 01679 } 01680 } 01681 }
|
|
Inserts a straight curve into the path. It keeps it as a curve so that the path will continue to look smooth after it is edited. If this is the last Path element in the fit, (ie Depth is zero) then the rotate flag will not be set. Scope: private.
Definition at line 1706 of file tracergn.cpp. 01708 { 01709 // Prepare some flags 01710 PathFlags Flags; 01711 Flags.IsSelected = FALSE; 01712 Flags.IsSmooth = FALSE; 01713 Flags.IsRotate = TRUE; 01714 01715 // Find out a third of the distance between the two points 01716 DocCoord StartPos; 01717 DocCoord EndPos; 01718 01719 StartPos.x = (2 * Start.x + End.x) /3; 01720 StartPos.y = (2 * Start.y + End.y) /3; 01721 EndPos.x = (Start.x + 2 * End.x) /3; 01722 EndPos.y = (Start.y + 2 * End.y) /3; 01723 01724 // Add the line to the curve 01725 ThePath->InsertCurveTo( (DocCoord) StartPos, (DocCoord) EndPos, (DocCoord) End, &Flags); 01726 01727 // Patch up the path 01728 PathVerb * AllVerbs = ThePath->GetVerbArray(); 01729 PathFlags* AllFlags = ThePath->GetFlagArray(); 01730 INT32 NumCoords = ThePath->GetNumCoords(); 01731 ERROR3IF(NumCoords<4,"No initial moveto ?!"); 01732 01733 AllFlags[NumCoords-1].IsRotate = !IsEndCusp; // Endpoint 01734 AllFlags[NumCoords-2].IsRotate = !IsEndCusp; // 2nd ctl 01735 01736 if (AllVerbs[NumCoords-4] == PT_MOVETO) 01737 { 01738 AllFlags[NumCoords-3].IsRotate = FALSE; 01739 AllFlags[NumCoords-4].IsRotate = FALSE; 01740 } 01741 else 01742 { 01743 //BOOL IsStartCusp = AllFlags[NumCoords-5].IsRotate; 01744 01745 AllFlags[NumCoords-3].IsRotate = !IsStartCusp; 01746 AllFlags[NumCoords-4].IsRotate = !IsStartCusp; 01747 01748 01749 } 01750 01751 }
|
|
Inserts a straight Line into the path. This is used in cases where the Line segment must be kept as a straight line (ie by using Straight Line Mode of the FreeHand tool) Scope: private.
Definition at line 1770 of file tracergn.cpp. 01771 { 01772 // Prepare some flags 01773 PathFlags Flags; 01774 Flags.IsSelected = FALSE; 01775 Flags.IsRotate = FALSE; 01776 Flags.IsSmooth = FALSE; 01777 01778 // Insert the line 01779 ThePath->InsertLineTo((DocCoord) End, &Flags); 01780 }
|
|
Definition at line 423 of file tracergn.h. 00424 { return (((dir1-dir2+TR_NUMDIRECTIONMASK+2) & TR_NUMDIRECTIONMASK)>2); }
|
|
Finds the Left tangent at the given point in the path Scope: private.
Definition at line 1514 of file tracergn.cpp. 01515 { 01516 TraceBoundaryPoint Tangent(0,0); 01517 01518 Points = 1+MIN (Points/2,MAXTANGENTPOINTS); 01519 if (Points<2) Points=2; 01520 01521 // Make sure that is not of zero length 01522 while ((Tangent.x==0) && (Tangent.y==0)) 01523 { 01524 if ((--Points)>0) 01525 { 01526 Tangent.x = BoundaryBuffer[Start+Points].x - BoundaryBuffer[Start].x; 01527 Tangent.y = BoundaryBuffer[Start+Points].y - BoundaryBuffer[Start].y; 01528 } 01529 else 01530 { 01531 ERROR3("Tangent was a zero length vector in the curve fitter (Left)"); 01532 Tangent.x = -1; 01533 } 01534 } 01535 01536 return Tangent; 01537 }
|
|
This function determines the TPoints which will be fitted (i.e. the trace boundary points we use) and the TValues which will be assigned to them (i.e. the t values along the chord length to which the points correspond). Scope: private.
Definition at line 1215 of file tracergn.cpp. 01216 { 01217 INT32 pos, i; 01218 01219 INT32 NumPoints = LastPoint-FirstPoint; 01220 // Chord length parameterisation 01221 01222 NumTPoints = MIN(NumPoints, FIT_STEPS); 01223 01224 for (pos=0; pos<=NumTPoints; pos++) 01225 { 01226 i = (INT32)(((double)pos/(double)NumTPoints*(double)(NumPoints))+0.5); 01227 // In this loop, 01228 TValues[pos] = ((double)i)/((double)NumPoints); 01229 TPoints[pos] = (i+FirstPoint); 01230 } 01231 01232 // These should algorithmically never happen 01233 ERROR3IF(TPoints[0]!=FirstPoint,"TraceRegion::Parameterize fouled up first point"); 01234 ERROR3IF(TPoints[NumTPoints]!=LastPoint,"TraceRegion::Parameterize fouled up last point"); 01235 return; 01236 }
|
|
Empties the boundary buffer.
Definition at line 951 of file tracergn.cpp. 00952 { 00953 BoundaryTail = 0; 00954 // ERROR3IF( (((BoundaryHead - BoundaryTail) & BoundaryRingMask) <=0 ), 00955 // "Boundary ring buffer is empty"); 00956 if (((BoundaryHead - BoundaryTail) & BoundaryRingMask) <=0 ) return TRUE; 00957 00958 if (VirginPath) 00959 { 00960 ThePath->FindStartOfPath(); 00961 ThePath->InsertMoveTo(DocCoord((INT32)(BoundaryBuffer[BoundaryTail].x), (INT32)(BoundaryBuffer[BoundaryTail].y))); 00962 VirginPath = FALSE; 00963 FirstBufferPoint=BoundaryBuffer[BoundaryTail]; 00964 } 00965 00966 // Patch up initial hinting (done on inadequate information) 00967 if (Done) 00968 { 00969 BoundaryBuffer[BoundaryHead-1]=FirstBufferPoint; 00970 if (BoundaryBuffer[BoundaryHead-2]==FirstBufferPoint) BoundaryHead=(BoundaryHead-1)&BoundaryRingMask; 00971 if (((BoundaryHead - BoundaryTail) & BoundaryRingMask) <=0 ) return TRUE; 00972 } 00973 00974 #if 0 00975 while (BoundaryTail != (BoundaryHead-1)) 00976 { 00977 InsertLine(DocCoord((INT32)(BoundaryBuffer[BoundaryTail].x),(INT32)(BoundaryBuffer[BoundaryTail].y)), 00978 DocCoord((INT32)(BoundaryBuffer[BoundaryTail=(BoundaryTail + 1) & BoundaryRingMask].x), 00979 (INT32)(BoundaryBuffer[BoundaryTail].y)), TRUE, TRUE); 00980 } 00981 #else 00982 // This case should never occur, but does very very occasionally - not sure why (Alex) 00983 // we ignore buffers with only one point in 00984 if (((BoundaryHead-1) & BoundaryRingMask)==BoundaryTail) return TRUE; 00985 00986 // Just have to fit a curve from the last cusp to the end of the path 00987 TraceBoundaryPoint Tangent1 = LeftTangent(BoundaryTail,BoundaryHead-BoundaryTail); 00988 TraceBoundaryPoint Tangent2 = RightTangent(BoundaryHead-1,BoundaryHead-BoundaryTail); 00989 00990 // and do a load of maths that will hopefully fit a nice curve on it 00991 FitCubic(BoundaryTail, BoundaryHead-1, Tangent1, Tangent2, TailCusp, AtCusp); 00992 #endif 00993 00994 BoundaryBuffer[0]=BoundaryBuffer[BoundaryHead-1]; 00995 BoundaryTail = 0; 00996 BoundaryHead = 1; 00997 00998 TailDirection = -1; 00999 TailCusp = AtCusp; 01000 return (TRUE); 01001 }
|
|
Finds the Right tangent at the given point in the path Scope: private.
Definition at line 1554 of file tracergn.cpp. 01555 { 01556 TraceBoundaryPoint Tangent(0,0); 01557 01558 Points = 1+MIN (Points/2,MAXTANGENTPOINTS); 01559 if (Points<2) Points=2; 01560 01561 // Make sure that is not of zero length 01562 while ((Tangent.x==0) && (Tangent.y==0)) 01563 { 01564 if ((--Points)>0) 01565 { 01566 Tangent.x = BoundaryBuffer[End-Points].x - BoundaryBuffer[End].x; 01567 Tangent.y = BoundaryBuffer[End-Points].y - BoundaryBuffer[End].y; 01568 } 01569 else 01570 { 01571 ERROR3("Tangent was a zero length vector in the curve fitter (Right)"); 01572 Tangent.x = -1; 01573 } 01574 } 01575 01576 return Tangent; 01577 }
|
|
Sets the tracing parameters.
Definition at line 393 of file tracergn.cpp. 00394 { 00395 if (pPixelError) PixelError = *pPixelError; 00396 Error = PixelError; 00397 Error *= 256.0; // For shift 00398 Error *= Error; // Squared 00399 00400 return TRUE; 00401 }
|
|
Internal test routine.
Definition at line 1802 of file tracergn.cpp. 01803 { 01804 01805 BOOL CarryOn=TRUE; 01806 Range Sel(*(GetApplication()->FindSelection())); 01807 01808 Node* FirstSelectedNode = Sel.FindFirst(); 01809 if (FirstSelectedNode != NULL) // No nodes selected so End 01810 { 01811 Node* CurrentNode = FirstSelectedNode; 01812 Node* NextCurrent; 01813 01814 // Do all bitmaps 01815 while ((CurrentNode != NULL) && CarryOn) 01816 { 01817 NextCurrent = Sel.FindNext(CurrentNode); 01818 if ( (CurrentNode->IsSelected()) && (CurrentNode->GetRuntimeClass() == CC_RUNTIME_CLASS(NodeBitmap)) ) 01819 { 01820 KernelBitmap * pBitmap = ((NodeBitmap *)(CurrentNode))->GetBitmap(); 01821 BitmapInfo BMInfo; 01822 UINT32 bpp; 01823 pBitmap->ActualBitmap->GetInfo(&BMInfo); 01824 bpp=BMInfo.PixelDepth; 01825 01826 TRACEUSER( "Alex", _T("Bitmap found %d bpp\n"),bpp); 01827 01828 if ((bpp==32) || TRUE) 01829 { 01830 CarryOn = FALSE; 01831 // NodeBitmap *pNodeBitmap = new NodeBitmap; 01832 // if ((pNodeBitmap == NULL) || (!pNodeBitmap->SetUpPath(12,12))) 01833 // return; 01834 01835 Spread *pSpread; 01836 DocCoord Origin; 01837 01838 // For now, position Draw objects on 1st page of spread 1 01839 Node *pNode = (Document::GetSelected())->GetFirstNode()->FindNext()->FindFirstChild(); 01840 while ((pNode != NULL) && (!pNode->IsKindOf(CC_RUNTIME_CLASS(Chapter)))) 01841 pNode = pNode->FindNext(); 01842 01843 ENSURE(pNode->IsKindOf(CC_RUNTIME_CLASS(Chapter)), 01844 "Filter::GetFirstSpread(): Could not find Chapter"); 01845 Chapter *pChapter = (Chapter *) pNode; 01846 01847 // pSpread is a child of pChapter 01848 pSpread = (Spread *) pChapter->FindFirstChild(); 01849 ENSURE(pSpread->IsKindOf(CC_RUNTIME_CLASS(Spread)), 01850 "Filter::GetFirstSpread(): Could not find Spread"); 01851 01852 Page *pPage = (Page *) pSpread->FindFirstPageInSpread(); 01853 ENSURE(pPage->IsKindOf(CC_RUNTIME_CLASS(Page)), 01854 "BaseBitmapFilter::DoImport(): Could not find first Page"); 01855 01856 // Use bottom left of page as origin 01857 DocRect PageRect = pPage->GetPageRect(); 01858 Origin = PageRect.lo; 01859 01860 NodePath * pNewNode; 01861 pNewNode = new NodePath; 01862 01863 TraceRegion TR; 01864 01865 // if ((pNode = TR->Trace(pBitmap,((NodeBitmap *)(CurrentNode))->Parallel)) == NULL) {return;} 01866 01867 TR.UseBitmap(pBitmap); 01868 TR.UsePath(&(pNewNode->InkPath)); 01869 TR.TraceBoundary(((NodeBitmap * )CurrentNode)->Parallel[3], 01870 ((NodeBitmap * )CurrentNode)->Parallel[2], 01871 ((NodeBitmap * )CurrentNode)->Parallel[0]); 01872 01873 // Insert the node, but don't invalidate its region 01874 if (!Op->DoInsertNewNode(pNewNode, pSpread, FALSE)) 01875 { 01876 // It didn't work - delete the sub-tree we just created, and report error. 01877 delete pNewNode; 01878 return; 01879 } 01880 01881 // Invalidate the region 01882 Op->DoInvalidateNodeRegion(pNewNode, TRUE, FALSE); 01883 01884 } 01885 } 01886 CurrentNode = NextCurrent; 01887 } 01888 01889 } 01890 01891 // if (CarryOn) BitmapEffectSILT::RunA(); 01892 01893 return; 01894 }
|
|
Does a single boundary trace.
Definition at line 743 of file tracergn.cpp. 00744 { 00745 BOOL Done=FALSE; 00746 ERROR2IF((!Bitmap),FALSE,"How about giving us a bitmap first then?"); 00747 00748 pBfxPixelOp = thepBfxPixelOp; 00749 00750 ERROR2IF( ((!pBfxPixelOp->IsInRegion(InitialX,InitialY))), FALSE, "Initial point not in region" ); 00751 00752 BOOL Bottom=FALSE; 00753 while (!Bottom) 00754 { 00755 Bottom=TRUE; 00756 if (pBfxPixelOp->IsInRegion(InitialX-1,InitialY-1)) 00757 { 00758 InitialY--; 00759 InitialX--; 00760 Bottom=FALSE; 00761 } 00762 if (pBfxPixelOp->IsInRegion(InitialX,InitialY-1)) 00763 { 00764 InitialY--; 00765 Bottom=FALSE; 00766 } 00767 if (pBfxPixelOp->IsInRegion(InitialX-1,InitialY)) 00768 { 00769 InitialX--; 00770 Bottom=FALSE; 00771 } 00772 } 00773 00774 InitialDirection = 4; // West 00775 VirginBuffer = TRUE; 00776 BoundaryHead =0; 00777 BoundaryTail =0; 00778 TailDirection = -1; 00779 HeadDirection = 4; 00780 AtCusp=FALSE; 00781 TailCusp = FALSE; 00782 00783 InitialPoint.x = InitialX<<8; 00784 InitialPoint.y = InitialY<<8; 00785 HeadPoint = FirstBufferPoint = InitialPoint; 00786 00787 do 00788 { 00789 if (!FillBoundaryBuffer(&Done)) return (FALSE); 00790 if (!VirginBuffer) { if (!ProcessBoundaryBuffer(Done)) return (FALSE); } else BoundaryHead=0; 00791 } while (!Done); 00792 00793 ERROR2IF(VirginPath, FALSE, "We've just traced a path that wasn't a path. Very odd"); 00794 00795 ThePath->CloseSubPath(); 00796 ThePath->IsFilled = TRUE; // What lovely encapsulation & abstraction... 00797 00798 return (TRUE); 00799 }
|
|
Does a single boundary trace.
Definition at line 699 of file tracergn.cpp. 00700 { 00701 BOOL Done; 00702 ERROR2IF((!Bitmap),FALSE,"How about giving us a bitmap first then?"); 00703 00704 // First find the initial point 00705 if (!(FindInitialPoint(&Done))) return (FALSE); 00706 if (Done) return (TRUE); 00707 00708 do 00709 { 00710 if (!FillBoundaryBuffer(&Done)) return (FALSE); 00711 if (!ProcessBoundaryBuffer(Done)) return (FALSE); 00712 } while (!Done); 00713 00714 ThePath->CloseSubPath(); 00715 ThePath->IsFilled = TRUE; // What lovely encapsulation & abstraction... 00716 00717 Matrix tMatrix(Div32By32(Point1.x-Origin.x,xsize<<8),Div32By32(Point2.x-Origin.x,xsize<<8), 00718 Div32By32(Point1.y-Origin.y,ysize<<8),Div32By32(Point2.y-Origin.y,ysize<<8), 00719 Origin.x,Origin.y); 00720 Trans2DMatrix Trans(tMatrix); 00721 Trans.Transform( (DocCoord*)ThePath->GetCoordArray(), ThePath->GetNumCoords() ); 00722 00723 return (TRUE); 00724 }
|
|
Points the TraceRegion at a particular bitmap and claims the relevant size buffers.
Note (surprisingly, perhaps) we don't actually ever refer to pixels within this bitmap. Only its size is used. The BfxPixelOp does all the poking around and it may be referencing a different (but same sized) bitmap elsewhere. Definition at line 538 of file tracergn.cpp. 00539 { 00540 if (BoundaryBuffer) 00541 { 00542 CCFree(BoundaryBuffer); 00543 BoundaryBuffer = NULL; 00544 } 00545 00546 xsize=1; 00547 ysize=1; 00548 Bitmap = NULL; 00549 00550 if (pBitmap) 00551 { 00552 INT32 MaxDimension; 00553 BitmapInfo BMInfo; 00554 pBitmap->ActualBitmap->GetInfo(&BMInfo); 00555 00556 // Max dimension is 8 times the largest of the width and height (enough to fit a bezier 00557 // curve of maximal usefulness into half the buffer) 00558 MaxDimension = ((BMInfo.PixelWidth>BMInfo.PixelHeight)?BMInfo.PixelWidth:BMInfo.PixelHeight)*8; 00559 ERROR2IF(MaxDimension<=0, FALSE, "Bitmap info structure is dead"); 00560 BoundaryRingSize = 1; 00561 00562 if (MaxDimension<80) MaxDimension=80; 00563 00564 // Get next highest power of 2 & mask 00565 while (BoundaryRingSize < MaxDimension) BoundaryRingSize = BoundaryRingSize<<1; 00566 BoundaryRingMask = BoundaryRingSize -1; 00567 00568 // Allocate memory (CCMalloc sets error) 00569 if (NULL== (BoundaryBuffer=(TraceBoundaryPoint *)CCMalloc(sizeof(TraceBoundaryPoint) * BoundaryRingSize)) ) 00570 return FALSE; 00571 // // fill the memory up with +S-NAN 00572 // for (INT32 i=0; i<BoundaryRingSize; i++) 00573 // { 00574 // INT32* p = (INT32*)&(BoundaryBuffer[i].x); 00575 // *p++ = 0xFFFFFFFF; 00576 // *p++ = 0x7FF7FFFF; 00577 // p = (INT32*)&(BoundaryBuffer[i].y); 00578 // *p++ = 0xFFFFFFFF; 00579 // *p++ = 0x7FF7FFFF; 00580 // } 00581 00582 xsize = BMInfo.PixelWidth; 00583 ysize = BMInfo.PixelHeight; 00584 Bitmap=pBitmap; 00585 VirginBuffer = TRUE; 00586 TailDirection = -1; 00587 BoundaryHead =0; 00588 BoundaryTail =0; 00589 TailDirection = 0; 00590 HeadDirection = 0; 00591 InitialDirection = 0; 00592 AtCusp = FALSE; 00593 TailCusp = FALSE; 00594 } 00595 return (TRUE); 00596 }
|
|
Specifies we should use a particular path. The path is initialised, cleared etc.
Definition at line 615 of file tracergn.cpp. 00616 { 00617 ThePath = NULL; 00618 VirginPath = TRUE; 00619 00620 if (pPath) 00621 { 00622 // if (!pPath->Initialise()) return FALSE; 00623 if (!pPath->ClearPath()) return FALSE; 00624 ThePath = pPath; 00625 } 00626 return (TRUE); 00627 }
|
|
Definition at line 408 of file tracergn.h. |
|
Definition at line 386 of file tracergn.h. |
|
Definition at line 383 of file tracergn.h. |
|
Definition at line 399 of file tracergn.h. |
|
Definition at line 400 of file tracergn.h. |
|
Definition at line 401 of file tracergn.h. |
|
Definition at line 398 of file tracergn.h. |
|
Definition at line 414 of file tracergn.h. |
|
Definition at line 413 of file tracergn.h. |
|
Definition at line 403 of file tracergn.h. |
|
Definition at line 396 of file tracergn.h. |
|
Definition at line 394 of file tracergn.h. |
|
Definition at line 391 of file tracergn.h. |
|
Definition at line 392 of file tracergn.h. |
|
Definition at line 390 of file tracergn.h. |
|
Definition at line 419 of file tracergn.h. |
|
Definition at line 384 of file tracergn.h. |
|
Definition at line 404 of file tracergn.h. |
|
Definition at line 418 of file tracergn.h. |
|
Definition at line 418 of file tracergn.h. |
|
Definition at line 409 of file tracergn.h. |
|
Definition at line 393 of file tracergn.h. |
|
Definition at line 411 of file tracergn.h. |
|
Definition at line 417 of file tracergn.h. |
|
Definition at line 416 of file tracergn.h. |
|
Definition at line 406 of file tracergn.h. |
|
Definition at line 407 of file tracergn.h. |
|
Definition at line 387 of file tracergn.h. |
|
Definition at line 388 of file tracergn.h. |