00001 // $Id: pathproc.cpp 1282 2006-06-09 09:46:49Z alex $ 00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE 00003 ================================XARAHEADERSTART=========================== 00004 00005 Xara LX, a vector drawing and manipulation program. 00006 Copyright (C) 1993-2006 Xara Group Ltd. 00007 Copyright on certain contributions may be held in joint with their 00008 respective authors. See AUTHORS file for details. 00009 00010 LICENSE TO USE AND MODIFY SOFTWARE 00011 ---------------------------------- 00012 00013 This file is part of Xara LX. 00014 00015 Xara LX is free software; you can redistribute it and/or modify it 00016 under the terms of the GNU General Public License version 2 as published 00017 by the Free Software Foundation. 00018 00019 Xara LX and its component source files are distributed in the hope 00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the 00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00022 See the GNU General Public License for more details. 00023 00024 You should have received a copy of the GNU General Public License along 00025 with Xara LX (see the file GPL in the root directory of the 00026 distribution); if not, write to the Free Software Foundation, Inc., 51 00027 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 00028 00029 00030 ADDITIONAL RIGHTS 00031 ----------------- 00032 00033 Conditional upon your continuing compliance with the GNU General Public 00034 License described above, Xara Group Ltd grants to you certain additional 00035 rights. 00036 00037 The additional rights are to use, modify, and distribute the software 00038 together with the wxWidgets library, the wxXtra library, and the "CDraw" 00039 library and any other such library that any version of Xara LX relased 00040 by Xara Group Ltd requires in order to compile and execute, including 00041 the static linking of that library to XaraLX. In the case of the 00042 "CDraw" library, you may satisfy obligation under the GNU General Public 00043 License to provide source code by providing a binary copy of the library 00044 concerned and a copy of the license accompanying it. 00045 00046 Nothing in this section restricts any of the rights you have under 00047 the GNU General Public License. 00048 00049 00050 SCOPE OF LICENSE 00051 ---------------- 00052 00053 This license applies to this program (XaraLX) and its constituent source 00054 files only, and does not necessarily apply to other Xara products which may 00055 in part share the same code base, and are subject to their own licensing 00056 terms. 00057 00058 This license does not apply to files in the wxXtra directory, which 00059 are built into a separate library, and are subject to the wxWindows 00060 license contained within that directory in the file "WXXTRA-LICENSE". 00061 00062 This license does not apply to the binary libraries (if any) within 00063 the "libs" directory, which are subject to a separate license contained 00064 within that directory in the file "LIBS-LICENSE". 00065 00066 00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS 00068 ---------------------------------------------- 00069 00070 Subject to the terms of the GNU Public License (see above), you are 00071 free to do whatever you like with your modifications. However, you may 00072 (at your option) wish contribute them to Xara's source tree. You can 00073 find details of how to do this at: 00074 http://www.xaraxtreme.org/developers/ 00075 00076 Prior to contributing your modifications, you will need to complete our 00077 contributor agreement. This can be found at: 00078 http://www.xaraxtreme.org/developers/contribute/ 00079 00080 Please note that Xara will not accept modifications which modify any of 00081 the text between the start and end of this header (marked 00082 XARAHEADERSTART and XARAHEADEREND). 00083 00084 00085 MARKS 00086 ----- 00087 00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara 00089 designs are registered or unregistered trademarks, design-marks, and/or 00090 service marks of Xara Group Ltd. All rights in these marks are reserved. 00091 00092 00093 Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK. 00094 http://www.xara.com/ 00095 00096 =================================XARAHEADEREND============================ 00097 */ 00098 // Implementation file for process path functions. These functions give paths 00099 // the ability to flatten themselves, find their lengths etc. 00100 00101 /* 00102 */ 00103 00104 #include "camtypes.h" 00105 #include "pathproc.h" 00106 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00107 //#include "paths.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00108 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED] 00109 #if !defined(EXCLUDE_FROM_XARLIB) 00110 #include "pen.h" 00111 #else 00112 #define MAXPRESSURE 1023 00113 #endif 00114 00115 DECLARE_SOURCE("$Revision: 1282 $"); 00116 00117 CC_IMPLEMENT_DYNAMIC(ProcessPath, CCObject); 00118 00119 // Declare smart memory handling in Debug builds 00120 #define new CAM_DEBUG_NEW 00121 00122 00123 00124 /****************************************************************************************** 00125 00126 > ProcessFlags::ProcessFlags(BOOL flatten, BOOL quantise, BOOL quantiseall) 00127 00128 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00129 Created: 25/10/94 00130 Inputs: flat = if true flatten curves 00131 quantise = if true quantise lines 00132 Outputs: - 00133 Purpose: Construct a ProcessFlags object. The flags control the action of 00134 ProcessPath::Process() function 00135 00136 ******************************************************************************************/ 00137 00138 ProcessFlags::ProcessFlags(BOOL flatten, BOOL quantise, BOOL quantiseall) 00139 { 00140 FlattenCurves = flatten; 00141 QuantiseLines = quantise; 00142 QuantiseAll = quantiseall; 00143 } 00144 00145 00146 00147 00148 /****************************************************************************************** 00149 00150 > ProcessPath::ProcessPath(const double flat) 00151 00152 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00153 Created: 25/10/94 00154 Purpose: 00155 Inputs: flat = How flat the curves should be (around 64 is good) 00156 00157 ******************************************************************************************/ 00158 00159 ProcessPath::ProcessPath(const double flat) 00160 { 00161 ProcSource = NULL; 00162 ProcCache = NULL; 00163 ProcNumCached = 0; 00164 ProcFirstPoint = TRUE; 00165 ProcFlatness = flat; 00166 } 00167 00168 00169 00170 00171 /****************************************************************************************** 00172 00173 > ProcessPath::~ProcessPath() 00174 00175 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00176 Created: 25/10/94 00177 Inputs: - 00178 Outputs: - 00179 Purpose: ProcessPath class destructor 00180 00181 ******************************************************************************************/ 00182 00183 ProcessPath::~ProcessPath() 00184 { 00185 if (ProcCache) 00186 CCFree(ProcCache); 00187 } 00188 00189 00190 00191 /****************************************************************************************** 00192 00193 > BOOL ProcessPath::Init(Path* pSource) 00194 00195 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00196 Created: 25/10/94 00197 Purpose: 00198 00199 ******************************************************************************************/ 00200 00201 BOOL ProcessPath::Init(Path* pSource) 00202 { 00203 // Allocate a cache for ourselves 00204 // ProcCache = (INT32*) CCMalloc(PROC_CACHE_SIZE*sizeof(INT32)); 00205 // if (ProcCache == NULL) 00206 // return FALSE; 00207 00208 ProcSource = pSource; 00209 return TRUE; 00210 } 00211 00212 00213 00214 00215 /****************************************************************************************** 00216 00217 > BOOL ProcesPath::Process(const ProcessFlags& PFlags) 00218 00219 Inputs: PFlags = Flags to direct the action of this function 00220 Outputs: 00221 Returns: BOOL = TRUE if the path was successfully processed 00222 = FALSE if something failed during the process 00223 00224 Purpose: Processes a path. It will scan through the elements of a path, passing 00225 points to a NewPoint virtual function. It will also flatten curves if 00226 found and pass the generated points on as well. 00227 00228 Quantise a path to an output path. The output path may already contain 00229 data, if so the quantised data will be added on the end. 00230 If the output path points to 'this' path, then having successfully quantised 00231 to the end of the output path, the original data in the buffer will be 00232 removed. This allows you to quantise a path to itself. 00233 If the routine fails, all quantisation data so far created by the routine 00234 will be removed. 00235 00236 ******************************************************************************************/ 00237 00238 BOOL ProcessPath::Process(const ProcessFlags& PFlags) 00239 { 00240 00241 // The idea here is that we create a quantised path. This means we 00242 // scan through the path descretizing curves and lines dependent 00243 // on the flatness value given. 00244 00245 DocCoord* ICoords = ProcSource->GetCoordArray(); 00246 PathVerb* IVerbs = ProcSource->GetVerbArray(); 00247 00248 INT32 numinsource = ProcSource->GetNumCoords(); 00249 00250 INT32 i=0; 00251 BOOL ok = TRUE; 00252 00253 // scan through the input verbs 00254 while ((i<numinsource) && (ok)) 00255 { 00256 switch (IVerbs[i] & ~PT_CLOSEFIGURE) 00257 { 00258 case PT_MOVETO: 00259 OpenElement(PT_MOVETO, i); 00260 ok = NewPoint(PT_MOVETO, &ICoords[i]); 00261 if (CloseElement(ok, PT_MOVETO, i)) 00262 i=(numinsource-1); 00263 break; 00264 00265 case PT_LINETO: 00266 { 00267 BOOL IsCloseFigure = ((IVerbs[i] & PT_CLOSEFIGURE) != 0); // Remember if this is the closing element 00268 00269 OpenElement(PT_LINETO, i); 00270 if (!PFlags.QuantiseAll) 00271 { 00272 if (!PFlags.QuantiseLines) 00273 ok = NewPoint(PT_LINETO, &ICoords[i]); 00274 else 00275 { 00276 DocCoord End = ICoords[i]; 00277 for (double mu = 0.2; (mu<1.2) && ok; mu+=0.2 ) 00278 { 00279 DocCoord dest; 00280 dest.x = (INT32)((1-mu)*ProcPreviousEl.x + mu*End.x); 00281 dest.y = (INT32)((1-mu)*ProcPreviousEl.y + mu*End.y); 00282 ok = NewPoint(PT_LINETO, &dest); 00283 } 00284 } 00285 } 00286 else 00287 { 00288 ok = InsertQuantisedLineTo(&ICoords[i], &ProcPreviousEl); 00289 } 00290 if (CloseElement(ok, PT_LINETO, i)) 00291 i=(numinsource-1); 00292 else if (IsCloseFigure) // If continuing, and this is the end of a closed figure 00293 CloseFigure(); // then close it off 00294 } 00295 break; 00296 00297 case PT_BEZIERTO: 00298 { 00299 BOOL IsCloseFigure = ((IVerbs[i+2] & PT_CLOSEFIGURE) != 0); // Remember if this is the closing element 00300 00301 OpenElement(PT_BEZIERTO, i); 00302 if (!PFlags.FlattenCurves) 00303 ok = NewPoint(PT_BEZIERTO, &ICoords[i]); 00304 else 00305 { 00306 ok = FlattenCurve(ProcPreviousEl.x, ProcPreviousEl.y, 00307 ICoords[i].x, ICoords[i].y, 00308 ICoords[i+1].x, ICoords[i+1].y, 00309 ICoords[i+2].x, ICoords[i+2].y, (PFlags.QuantiseAll) ); 00310 } 00311 if (CloseElement(ok, PT_BEZIERTO, i)) 00312 i=(numinsource-1); 00313 else 00314 { 00315 if (IsCloseFigure) // If continuing, and this is the end of a closed figure 00316 CloseFigure(); // then close it off 00317 00318 i+=2; 00319 } 00320 } 00321 break; 00322 00323 default: ERROR3("ProcessPath::Process() - unknown path verb!"); 00324 00325 } 00326 ICoords = ProcSource->GetCoordArray(); 00327 IVerbs = ProcSource->GetVerbArray(); 00328 i++; 00329 ProcFirstPoint = FALSE; 00330 ProcPreviousEl = ICoords[i-1]; 00331 } 00332 return ok; 00333 } 00334 00335 /******************************************************************************************** 00336 00337 > BOOL ProcessPath::FlattenCurve(INT32 Px0,INT32 Py0, 00338 INT32 Px1,INT32 Py1, 00339 INT32 Px2,INT32 Py2, 00340 INT32 Px3,INT32 Py3) 00341 00342 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00343 Created: 25/10/93 00344 Inputs: Px0-Py3 = These are the x and y coords for the 4 control points of 00345 a bezier 00346 Outputs: - 00347 Purpose: Generates a set of points on the bezier curve specified. The points start 00348 at (Px0,Py0) and traverse the curve to (Px3,Py3). If the points are joined 00349 with straight lines, the lines (given a good flatness value) should 00350 approximate the curve accurately enough to appear continuous. Obviously this 00351 is soley dependent on the flat value passed to the function. A value around 00352 64 is a good approximator. 00353 00354 ********************************************************************************************/ 00355 00356 BOOL ProcessPath::FlattenCurve( INT32 Px0,INT32 Py0, 00357 INT32 Px1,INT32 Py1, 00358 INT32 Px2,INT32 Py2, 00359 INT32 Px3,INT32 Py3, BOOL QuantiseAll) 00360 { 00361 INT32 diff; 00362 00363 INT32 dx0 = (Px1*3 - Px0*2 - Px3); 00364 if (dx0 < 0) dx0 = -dx0; 00365 //dx0 = dx0 < 0 ? -dx0 : dx0; 00366 00367 INT32 dy0 = (Py1*3 - Py0*2 - Py3); 00368 if (dy0 < 0) dy0 = -dy0; 00369 //dy0 = dy0 < 0 ? -dy0 : dy0; 00370 00371 // Get the line's distance from the curve 00372 if (dx0 >= dy0) 00373 diff = 3*dx0 + dy0; 00374 else 00375 diff = dx0 + 3*dy0; 00376 00377 // Is the straight line close enough to the curve ? 00378 if (diff > ProcFlatness) 00379 { 00380 // Not close enough so split it into two and recurse for each half 00381 BOOL ok = FlattenSplit(Px0,Py0, Px1,Py1, Px2,Py2, Px3,Py3, QuantiseAll); 00382 return ok; 00383 } 00384 00385 INT32 dx1 = (Px2*3 - Px0 - Px3*2); 00386 if (dx1 < 0) dx1 = -dx1; 00387 //dx1 = dx1 < 0 ? -dx1 : dx1; 00388 00389 INT32 dy1 = (Py2*3 - Py0 - Py3*2); 00390 if (dy1 < 0) dy1 = -dy1; 00391 //1 = dy1 < 0 ? -dy1 : dy1; 00392 00393 // Get the line's distance from the curve 00394 if (dx1 >= dy1) 00395 diff = 3*dx1 + dy1; 00396 else 00397 diff = dx1 + 3*dy1; 00398 00399 // Is the straight line close enough to the curve ? 00400 if (diff > ProcFlatness) 00401 { 00402 // Not close enough so split it into two and recurse for each half 00403 BOOL ok = FlattenSplit(Px0,Py0, Px1,Py1, Px2,Py2, Px3,Py3, QuantiseAll); 00404 return ok; 00405 } 00406 00407 DocCoord npoint; 00408 npoint.x = Px3; 00409 npoint.y = Py3; 00410 00411 // Line is now close enough so call the virtual function 00412 if (!QuantiseAll) 00413 return NewPoint(PT_LINETO, &npoint); 00414 else 00415 { 00416 DocCoord spoint; 00417 spoint.x = Px0; 00418 spoint.y = Py0; 00419 return InsertQuantisedLineTo(&npoint,&spoint); 00420 } 00421 } 00422 00423 00424 00425 /****************************************************************************************** 00426 00427 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00428 Created: 25/10/93 00429 Purpose: Recursive partner to FlattenCurve. 00430 NOT to be called by anything other than FlattenCurve. 00431 00432 ******************************************************************************************/ 00433 00434 BOOL ProcessPath::FlattenSplit(INT32 Px0,INT32 Py0, 00435 INT32 Px1,INT32 Py1, 00436 INT32 Px2,INT32 Py2, 00437 INT32 Px3,INT32 Py3, BOOL QuantiseAll) 00438 { 00439 00440 // Calculate the first half of the curve 00441 INT32 lx0 = Px0; 00442 INT32 ly0 = Py0; 00443 INT32 lx1 = (Px0 + Px1)/2; 00444 INT32 ly1 = (Py0 + Py1)/2; 00445 INT32 lx2 = (Px0 + 2*Px1 + Px2)/4; 00446 INT32 ly2 = (Py0 + 2*Py1 + Py2)/4; 00447 INT32 lx3 = (Px0 + 3*Px1 + 3*Px2 + Px3)/8; 00448 INT32 ly3 = (Py0 + 3*Py1 + 3*Py2 + Py3)/8; 00449 00450 // Calculate the second half of the curve 00451 INT32 rx0 = lx3; 00452 INT32 ry0 = ly3; 00453 INT32 rx1 = (Px1 + 2*Px2 + Px3)/4; 00454 INT32 ry1 = (Py1 + 2*Py2 + Py3)/4; 00455 INT32 rx2 = (Px2 + Px3)/2; 00456 INT32 ry2 = (Py2 + Py3)/2; 00457 INT32 rx3 = Px3; 00458 INT32 ry3 = Py3; 00459 00460 // Recurse for both halfs of the curve 00461 BOOL ok = FlattenCurve(lx0,ly0, lx1,ly1, lx2,ly2, lx3,ly3, QuantiseAll); 00462 if (ok) ok = FlattenCurve(rx0,ry0, rx1,ry1, rx2,ry2, rx3,ry3, QuantiseAll); 00463 00464 return ok; 00465 } 00466 00467 /****************************************************************************************** 00468 00469 Author: Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com> 00470 Created: 29/03/95 00471 Purpose: inserts a quantised lineto 00472 00473 ******************************************************************************************/ 00474 00475 BOOL ProcessPath::InsertQuantisedLineTo(DocCoord * pEnd, DocCoord * pStart) 00476 { 00477 INT32 dx = pEnd->x - pStart->x; 00478 INT32 dy = pEnd->y - pStart->y; 00479 INT32 pdx = (dx<0)?(-dx):dx; 00480 INT32 pdy = (dy<0)?(-dy):dy; 00481 INT32 maxdist = (pdx<pdy)?pdy:pdx; 00482 INT32 points = (INT32)((((double)maxdist/ProcFlatness)) + 0.5); 00483 if (points<=1) return NewPoint(PT_LINETO, pEnd); 00484 if (points>10) points=10; 00485 DocCoord intermediate; 00486 INT32 n; 00487 for (n=1; n<=points; n++) 00488 { 00489 double d=((double)n/(double)points); 00490 intermediate.x=pStart->x + (INT32)(0.5+d*(double)dx); 00491 intermediate.y=pStart->y + (INT32)(0.5+d*(double)dy); 00492 if (!NewPoint(PT_LINETO, &intermediate)) return FALSE; 00493 } 00494 return TRUE; 00495 } 00496 00497 /****************************************************************************************** 00498 00499 void ProcessPath::OpenElement(PathVerb Verb, INT32 index) 00500 00501 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00502 Created: 25/10/94 00503 Inputs: Verb = verb of opening element. 00504 index = index of opening element. 00505 Purpose: Does nothing 00506 00507 ******************************************************************************************/ 00508 00509 void ProcessPath::OpenElement(PathVerb Verb, INT32 index) 00510 { 00511 // Base class null function 00512 } 00513 00514 /****************************************************************************************** 00515 00516 BOOL ProcessDistance::CloseElement(BOOL done, PathVerb Verb, INT32 index) 00517 00518 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00519 Created: 1/11/94 00520 Inputs: done = true if the new point function procesed all new points in the 00521 open element correctly, 00522 false if it did not. 00523 Verb = verb of closing element. 00524 index = index of closing element. 00525 Outputs: 00526 Returns: FALSE to continue processing the next element 00527 TRUE to stop processing and return done 00528 Purpose: Does nothing 00529 00530 ******************************************************************************************/ 00531 00532 BOOL ProcessPath::CloseElement(BOOL done, PathVerb Verb, INT32 index) 00533 { 00534 // Base class null function 00535 return FALSE; 00536 } 00537 00538 /****************************************************************************************** 00539 00540 > virtual void ProcessPath::CloseFigure(void) 00541 00542 Author: Jason_Williams (Xara Group Ltd) <camelotdev@xara.com> 00543 Created: 16/1/97 00544 00545 Purpose: Derived-class interface. 00546 Called after closing a LINETO or BEZIERTO element which constitutes 00547 the end of this figure (subpath) (as indicated by this element having 00548 the PT_CLOSEFIGURE flag set). 00549 00550 Used by the path stroking ProcessPathToTrapezoids class to allow it 00551 to correctly handle joining the start & end of a closed figure. 00552 00553 The base class does nothing 00554 00555 SeeAlso: ProcessPathToTrapezoids::CloseFigure 00556 00557 ******************************************************************************************/ 00558 00559 void ProcessPath::CloseFigure(void) 00560 { 00561 } 00562 00563 00564 00565 00566 00567 00568 00569 00570 00571 /****************************************************************************************** 00572 00573 > ProcessFlatten::ProcessFlatten(const double flat) 00574 00575 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00576 Created: 25/10/94 00577 Inputs: flat = How flat the curves should be (around 64 is good) 00578 Purpose: Constructor for ProcessFlatten 00579 00580 ******************************************************************************************/ 00581 00582 ProcessFlatten::ProcessFlatten(const double flat) : ProcessPath(flat) 00583 { 00584 } 00585 00586 00587 /****************************************************************************************** 00588 00589 > BOOL ProcessFlatten::FlattenPath(const ProcessFlags& PFlags, Path* pSource, Path* pDestin) 00590 00591 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00592 Created: 25/10/94 00593 Inputs: PFlags = Flags to control ProcessPath 00594 pSource = a pointer to the path to flatten 00595 pDestin = a pointer to the path to take the flattened data 00596 Outputs: pDestin contains the flattened version of the path 00597 Returns: TRUE if the path was flattened successfully 00598 FALSE then an error was signalled during processing, possibly 00599 due to lack of memory. 00600 Purpose: Flatten a path object. 00601 SeeAlso: Path::Flatten() 00602 00603 ******************************************************************************************/ 00604 00605 BOOL ProcessFlatten::FlattenPath(const ProcessFlags& PFlags, Path* pSource, Path* pDestin) 00606 { 00607 BOOL ok = ProcessPath::Init(pSource); 00608 if (ok) 00609 { 00610 FlattenOutput = pDestin; 00611 FlattenOutput->SetPathPosition(pDestin->GetNumCoords()); 00612 ok = ProcessPath::Process(PFlags); 00613 } 00614 return ok; 00615 } 00616 00617 00618 /****************************************************************************************** 00619 00620 > BOOL ProcessFlatten::NewPoint(PathVerb Verb, DocCoord& Coord) 00621 00622 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00623 Created: 25/10/94 00624 Purpose: 00625 00626 ******************************************************************************************/ 00627 00628 BOOL ProcessFlatten::NewPoint(PathVerb Verb, DocCoord* pCoord) 00629 { 00630 if (Verb == PT_MOVETO) 00631 return FlattenOutput->AddMoveTo(*pCoord); 00632 00633 if (Verb == PT_LINETO) 00634 return FlattenOutput->AddLineTo(*pCoord); 00635 00636 return TRUE; 00637 } 00638 00639 00640 00641 00642 00643 /****************************************************************************************** 00644 00645 > ProcessLength::ProcessLength(const double flat) 00646 00647 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00648 Created: 25/10/94 00649 Purpose: Constructor for processlength. 00650 00651 ******************************************************************************************/ 00652 00653 ProcessLength::ProcessLength(const double flat) : ProcessPath(flat) 00654 { 00655 } 00656 00657 00658 /****************************************************************************************** 00659 00660 > BOOL ProcessLength::PathLength(Path* pSource, double* SqrLength, INT32 index = -1) 00661 00662 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00663 Created: 25/10/94 00664 Inputs: pSource = a pointer to a path 00665 Outputs SqrLength = the squared length of the path 00666 Purpose: Returns an approximation to the length of a path, in 72000 of an inch 00667 units. 00668 00669 ******************************************************************************************/ 00670 00671 BOOL ProcessLength::PathLength(Path* pSource, double* Length, INT32 index) 00672 { 00673 ERROR2IF(pSource==NULL, FALSE, "NULL path passed to ProcessLength::PathLength()"); 00674 if (index<0) 00675 index = (pSource->GetNumCoords())+1; 00676 00677 CurrLength = 0; 00678 ElementLength = 0; 00679 UserIndex = index; 00680 00681 ProcessFlags PFlags; 00682 BOOL ok = ProcessPath::Init(pSource); 00683 if (ok) ok = ProcessPath::Process(PFlags); 00684 if (ok) *Length = CurrLength; 00685 00686 return ok; 00687 } 00688 00689 00690 /****************************************************************************************** 00691 00692 void ProcessLength::OpenElement(PathVerb Verb, INT32 index) 00693 00694 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00695 Created: 25/10/94 00696 Inputs: Verb = verb of opening element. 00697 index = index of opening element. 00698 Purpose: Called from ProcessPath which is about to open a new path element. 00699 00700 ******************************************************************************************/ 00701 00702 void ProcessLength::OpenElement(PathVerb Verb, INT32 index) 00703 { 00704 ElementLength = 0; 00705 } 00706 00707 00708 /****************************************************************************************** 00709 00710 > BOOL ProcessLength::NewPoint(PathVerb Verb, DocCoord* pCoord) 00711 00712 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00713 Created: 25/10/94 00714 Purpose: 00715 00716 ******************************************************************************************/ 00717 00718 BOOL ProcessLength::NewPoint(PathVerb Verb, DocCoord* pCoord) 00719 { 00720 if (!ProcFirstPoint && Verb==PT_LINETO) 00721 { 00722 double p0 = PrevCoord.x - pCoord->x; 00723 double p1 = PrevCoord.y - pCoord->y; 00724 ElementLength += sqrt((p0*p0)+(p1*p1)); 00725 } 00726 PrevCoord = *pCoord; 00727 return TRUE; 00728 } 00729 00730 00731 00732 /****************************************************************************************** 00733 00734 BOOL ProcessLength::CloseElement(BOOL done, PathVerb Verb, INT32 index) 00735 00736 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00737 Created: 25/10/94 00738 Inputs: done = true if the new point function procesed all new points in the 00739 open element correctly, 00740 false if it did not. 00741 Verb = verb of closing element. 00742 index = index of closing element. 00743 Outputs: 00744 Returns: FALSE to continue processing the next element 00745 TRUE to stop processing and return done 00746 Purpose: This function is called after processing all new points on a path element. 00747 The path element being a curve or line segment within the path passed to 00748 ProcessDistance::PathDistance(). 00749 00750 ******************************************************************************************/ 00751 00752 BOOL ProcessLength::CloseElement(BOOL done, PathVerb Verb, INT32 index) 00753 { 00754 if (index>UserIndex) 00755 // terminate scan now 00756 return TRUE; 00757 00758 // continue summing element lengths 00759 CurrLength+=ElementLength; 00760 return FALSE; 00761 } 00762 00763 00764 00765 00766 00767 /****************************************************************************************** 00768 00769 > ProcessDistance::ProcessDistance(const double flat) 00770 00771 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00772 Created: 1/11/94 00773 Inputs: flat = flattness threshold to be used when processing the path 00774 Purpose: Constructor for processdistance. 00775 00776 ******************************************************************************************/ 00777 00778 ProcessDistance::ProcessDistance(const double flat) : ProcessPath(flat) 00779 { 00780 ElementLength = 0; 00781 ElementParam = 0; 00782 ElementIndex = 0; 00783 00784 00785 } 00786 00787 00788 /****************************************************************************************** 00789 00790 > double ProcessDistance::PathDistance(const double dist, Path* pSource, INT32* index) 00791 00792 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00793 Created: 1/11/94 00794 Inputs: sqrdist = a distance along the path pSource 00795 pSource = a pointer to a path 00796 00797 Outputs: index = the index of an element in the path 00798 Returns: double = an element parameter p where 0<=p<=1 such that p is the 00799 squared distance along the path pSource. 00800 Purpose: Returns information about a point, which lies a particular distance along 00801 a path. 00802 SeeAlso: Path::ClosestPointTo(), which will return a doccoord given a parameter p 00803 and index i. 00804 00805 ******************************************************************************************/ 00806 00807 double ProcessDistance::PathDistance(const double dist, Path* pSource, INT32* index) 00808 { 00809 ENSURE(dist>=0, "distance along path is negative in ProcessDistance::PathDistance"); 00810 00811 if (dist>0) 00812 Distance = dist; 00813 else 00814 Distance = 0; 00815 00816 // if we have a simple position then return the start 00817 if (Distance == 0) 00818 { 00819 *index = 0; 00820 return 0; 00821 } 00822 00823 // set up the processpath process. 00824 ProcessFlags PFlags; 00825 BOOL ok = ProcessPath::Init(pSource); 00826 if (ok) ok = ProcessPath::Process(PFlags); 00827 if (ok) *index = ElementIndex; 00828 00829 return ElementParam; 00830 } 00831 00832 00833 /****************************************************************************************** 00834 00835 void ProcessDistance::OpenElement(PathVerb Verb, INT32 index) 00836 00837 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00838 Created: 25/10/94 00839 Inputs: Verb = verb of opening element. 00840 index = index of opening element. 00841 Purpose: Called from ProcessPath which is about to open a new path element. 00842 00843 ******************************************************************************************/ 00844 00845 void ProcessDistance::OpenElement(PathVerb Verb, INT32 index) 00846 { 00847 ElementLength = 0; 00848 ElementParam = 0; 00849 ElementIndex = 0; 00850 } 00851 00852 00853 /****************************************************************************************** 00854 00855 BOOL ProcessDistance::NewPoint(PathVerb Verb, DocCoord* pCoord) 00856 00857 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00858 Created: 25/10/94 00859 Purpose: Called from ProcessPath which has generated a new point on the open 00860 element. 00861 00862 ******************************************************************************************/ 00863 00864 BOOL ProcessDistance::NewPoint(PathVerb Verb, DocCoord* pCoord) 00865 { 00866 if (!ProcFirstPoint) 00867 { 00868 double p0 = PrevCoord.x - pCoord->x; 00869 double p1 = PrevCoord.y - pCoord->y; 00870 ElementLength += sqrt((p0*p0)+(p1*p1)); 00871 } 00872 PrevCoord = *pCoord; 00873 return TRUE; 00874 } 00875 00876 00877 /****************************************************************************************** 00878 00879 BOOL ProcessDistance::CloseElement(BOOL done, PathVerb Verb, INT32 index) 00880 00881 Author: Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com> 00882 Created: 25/10/94 00883 Inputs: done = true if the new point function procesed all new points in the 00884 open element correctly, 00885 false if it did not. 00886 Verb = verb of closing element. 00887 index = index of closing element. 00888 Outputs: 00889 Purpose: This function is called after processing all new points on a path element. 00890 The path element being a curve or line segment within the path passed to 00891 ProcessDistance::PathDistance(). 00892 The function will use the element length calculated by NewPoint and 00893 decrement the total path length by this amount. If at some point the 00894 working distance goes negative, a parameter is calculated along the 00895 element. 00896 00897 ******************************************************************************************/ 00898 00899 BOOL ProcessDistance::CloseElement(BOOL done, PathVerb Verb, INT32 index) 00900 { 00901 if (done) 00902 { 00903 Distance-=ElementLength; 00904 INT32 nextindex = index; 00905 if ((Distance>0) && ProcSource->FindNextEndPoint(&nextindex)) 00906 return FALSE; 00907 00908 Distance+=ElementLength; 00909 ElementIndex = index; 00910 00911 if (ElementLength>0) 00912 ElementParam = Distance / ElementLength; 00913 else 00914 ElementParam = 0; 00915 00916 return TRUE; 00917 00918 } 00919 return FALSE; 00920 } 00921 00922 00923 00925 // ProcessPathDistance 00926 00927 /****************************************************************************************** 00928 > ProcessPathDistance::ProcessPathDistance(const double flat) 00929 00930 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00931 Created: 9/4/95 00932 Inputs: flat = flattness threshold to be used when processing the path 00933 Purpose: Constructor for ProcessPathDistance 00934 ******************************************************************************************/ 00935 00936 ProcessPathDistance::ProcessPathDistance(const double flat) : ProcessPath(flat) 00937 { 00938 // just calls base class for now 00939 00940 // initialise caching members - DY 00941 m_LastFoundIndex = 0; 00942 m_LastFoundDistance = 0; 00943 CurrentDist = 0.0; 00944 m_bDrawingBrush = FALSE; 00945 } 00946 00947 00948 /****************************************************************************************** 00949 > BOOL ProcessPathDistance::GetCoordAndTangent(DocCoord* pCoord, double* pTangent, 00950 BOOL* pFound, double Dist, Path* pPath) 00951 00952 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 00953 Created: 9/4/95 00954 Purpose: Find the coords and tangent at a distance along a path 00955 If the distance is not actually on the path, extrapolate the ends of the 00956 Inputs: Dist - distance along path for which info is desired 00957 pPath - path to process 00958 Outputs: pCoord - coord of desired distance along path 00959 pTangent - tangent of desired distance along path 00960 pFound - TRUE if point found (ie distance not longer than path) 00961 Returns: FALSE if fails 00962 path as lines at the tangent at the last points and flag not (really) found 00963 ******************************************************************************************/ 00964 00965 BOOL ProcessPathDistance::GetCoordAndTangent(DocCoord* pCoord, double* pTangent, BOOL* pFound, 00966 double Dist, Path* pPath, UINT32* pPressure) 00967 { 00968 ERROR2IF(pCoord==NULL && pTangent==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - no output pointers specified!"); 00969 ERROR2IF(pFound==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - pFound==NULL"); 00970 ERROR2IF( pPath==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - pPath==NULL"); 00971 00972 DesiredDist = Dist; 00973 CurrentDist = 0; 00974 Found = FALSE; 00975 CoordAtDist = DocCoord(0,0); 00976 TangentAtDist = 0; 00977 PressureAtDist = 0; 00978 00979 // set up the processpath process. 00980 ProcessFlags PFlags; 00981 BOOL ok=ProcessPath::Init(pPath); 00982 if (ok) ok= Process(PFlags, 0); //ProcessPath::Process(PFlags); 00983 00984 if (ok) 00985 { 00986 if (Found==FALSE) 00987 { 00988 // get last 2 points on line 00989 DocCoord* pPathCoords=pPath->GetCoordArray(); 00990 ERROR2IF(pPathCoords==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - pPathCoords==NULL"); 00991 INT32 NumPathCoords=pPath->GetNumCoords(); 00992 ERROR2IF(NumPathCoords<2,FALSE,"ProcessPathDistance::GetCoordAndTangent() - NumPathCoords < 2"); 00993 DocCoord LastCoord=pPathCoords[NumPathCoords-1]; 00994 DocCoord PrevCoord=pPathCoords[NumPathCoords-2]; 00995 00996 double dx=LastCoord.x-PrevCoord.x; 00997 double dy=LastCoord.y-PrevCoord.y; 00998 double LineLength=sqrt(dx*dx+dy*dy); 00999 01000 if (LineLength>0) 01001 { 01002 double FractOfLine = (DesiredDist-CurrentDist)/LineLength; 01003 double x = LastCoord.x+dx*FractOfLine; 01004 double y = LastCoord.y+dy*FractOfLine; 01005 01006 CoordAtDist = DocCoord((MILLIPOINT)x,(MILLIPOINT)y); 01007 TangentAtDist = atan2(dy,dx); 01008 } 01009 else 01010 { 01011 CoordAtDist = LastCoord; 01012 TangentAtDist = 0; 01013 } 01014 } 01015 else 01016 if (Dist<0) Found=FALSE; // if not actually on path, flag not found on path 01017 01018 01019 *pFound = Found; 01020 if (pCoord) *pCoord = CoordAtDist; 01021 if (pTangent) *pTangent = TangentAtDist; 01022 if (pPressure != NULL) 01023 { 01024 *pPressure = PressureAtDist; 01025 // TRACEUSER( "Diccon", _T("Pressure At Dist = %d\n"), PressureAtDist); 01026 } 01027 } 01028 01029 return ok; 01030 } 01031 01032 /****************************************************************************************** 01033 > INT32 ProcessPathDistance::GetCoordAndTangentWithCache(DocCoord* pCoord, double* pTangent, 01034 BOOL* pFound, double Dist, Path* pPath) 01035 01036 Author: Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com> 01037 Created: 9/4/95 01038 Inputs: Dist - distance along path for which info is desired 01039 pPath - path to process 01040 Outputs: pCoord - coord of desired distance along path 01041 pTangent - tangent of desired distance along path 01042 pFound - TRUE if point found (ie distance not longer than path) 01043 Returns: The number of coords processed, or -1 if failure 01044 Purpose: Find the coords and tangent at a distance along a path 01045 If the distance is not actually on the path, extrapolate the ends of the 01046 path as lines at the tangent at the last points and flag not (really) found 01047 This variant is designed for paths that use this function a lot. To avoid 01048 processsing the entire path many times we keep track of how many 01049 coords have already been processed. 01050 01051 Note: The caching currently only works if you are looking for consecutive points 01052 on the same path, for example whilst drawing a brush stroke. 01053 ******************************************************************************************/ 01054 01055 INT32 ProcessPathDistance::GetCoordAndTangentWithCache(DocCoord* pCoord, 01056 double* pTangent, BOOL* pFound, 01057 double Dist, Path* pPath, UINT32* pPressure) 01058 { 01059 ERROR2IF(pCoord==NULL && pTangent==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - no output pointers specified!"); 01060 ERROR2IF(pFound==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - pFound==NULL"); 01061 ERROR2IF( pPath==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - pPath==NULL"); 01062 01063 // we wish to continue processing from the last point that we found 01064 INT32 PrevCoordIndex = m_LastFoundIndex; 01065 INT32 NumProcessed = m_LastFoundIndex; 01066 01067 DesiredDist = Dist; 01068 CurrentDist = m_LastFoundDistance; 01069 Found = FALSE; 01070 CoordAtDist = DocCoord(0,0); 01071 TangentAtDist = 0; 01072 PressureAtDist = 0; 01073 m_bDrawingBrush = TRUE; 01074 // set up the processpath process. 01075 ProcessFlags PFlags; 01076 01077 BOOL bPressure = (pPressure != NULL && pPath->HasWidth()); 01078 // if we are already partway along the path then we need to get the 01079 // previous point as it is needed in NewPoint 01080 if (NumProcessed > 0) 01081 { 01082 DocCoord* pCoords = pPath->GetCoordArray(); 01083 PrevCoord = pCoords[PrevCoordIndex]; 01084 if (bPressure) 01085 { 01086 UINT32* pPressureArray = pPath->GetWidthArray(); 01087 if (pPressureArray != NULL) 01088 m_PrevPressure = pPressureArray[PrevCoordIndex]; 01089 else 01090 { 01091 ERROR3("Wheres the pressure array?"); 01092 m_PrevPressure = (UINT32)(MAXPRESSURE / 2); 01093 } 01094 } 01095 } 01096 01097 BOOL ok=ProcessPath::Init(pPath); 01098 //TRACEUSER( "Diccon", _T("Desired = %f\n"), Dist); 01099 //TRACEUSER( "Diccon", _T("Starting = %f\n"), CurrentDist); 01100 01101 if (ok) NumProcessed = Process(PFlags, NumProcessed); 01102 01103 if (NumProcessed != -1) 01104 { 01105 if (Found==FALSE) // this can happen if we are on the first couple of points 01106 { 01107 // get last 2 points on line 01108 DocCoord* pPathCoords=pPath->GetCoordArray(); 01109 ERROR2IF(pPathCoords==NULL,FALSE,"ProcessPathDistance::GetCoordAndTangent() - pPathCoords==NULL"); 01110 INT32 NumPathCoords=pPath->GetNumCoords(); 01111 //ERROR2IF(NumPathCoords<2,FALSE,"ProcessPathDistance::GetCoordAndTangent() - NumPathCoords < 2"); 01112 if (NumPathCoords >= 2) 01113 { 01114 DocCoord LastCoord=pPathCoords[NumPathCoords-1]; 01115 DocCoord PrevCoord=pPathCoords[NumPathCoords-2]; 01116 01117 double dx=LastCoord.x-PrevCoord.x; 01118 double dy=LastCoord.y-PrevCoord.y; 01119 double LineLength=sqrt(dx*dx+dy*dy); 01120 01121 if (LineLength>0) 01122 { 01123 double FractOfLine = (DesiredDist-CurrentDist)/LineLength; 01124 double x = LastCoord.x+dx*FractOfLine; 01125 double y = LastCoord.y+dy*FractOfLine; 01126 01127 CoordAtDist = DocCoord((MILLIPOINT)x,(MILLIPOINT)y); 01128 TangentAtDist = atan2(dy,dx); 01129 Found = TRUE; 01130 } 01131 else 01132 { 01133 CoordAtDist = LastCoord; 01134 TangentAtDist = 0; 01135 Found = TRUE; 01136 } 01137 } 01138 else //if we only have one coordinate so far 01139 { 01140 CoordAtDist=pPathCoords[0]; 01141 TangentAtDist = 0; 01142 Found = TRUE; 01143 } 01144 } 01145 else 01146 { 01147 if (Dist<0) Found=FALSE; // if not actually on path, flag not found on path 01148 01149 } 01150 *pFound = Found; 01151 if (pCoord) *pCoord = CoordAtDist; 01152 if (pTangent) *pTangent = TangentAtDist; 01153 if (pPressure != NULL) 01154 *pPressure = PressureAtDist; 01155 } 01156 //m_LastFoundDistance = CurrentDist; 01157 //TRACEUSER( "Diccon", _T("Last Index = %d\n"), m_LastFoundIndex); 01158 //TRACEUSER( "Diccon", _T("Last Dist = %f\n"), m_LastFoundDistance); 01159 01160 //TRACEUSER( "Diccon", _T("FOUND = %d\n"), Found); 01161 01162 return NumProcessed; 01163 } 01164 /****************************************************************************************** 01165 > BOOL ProcessPathDistance::NewPoint(PathVerb Verb, DocCoord* pCoord) 01166 01167 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01168 Created: 9/4/95 01169 Inputs: Verb - current point verb (only processes PT_LINETO) 01170 pCoord - current point coords 01171 Returns: TRUE 01172 Purpose: Called from ProcessPath which has generated a new point on the open element. 01173 If the length of this line causes the cummulaive length to exceed the 01174 desired length, get the tangent of this line then use the remaing distance 01175 (Desired-Current) to linearly interpolate to the desired coord on the line 01176 ******************************************************************************************/ 01177 01178 BOOL ProcessPathDistance::NewPoint(PathVerb Verb, DocCoord* pCoord) 01179 { 01180 ERROR2IF(pCoord==NULL,FALSE,"ProcessPathDistance::NewPoint() - pCoord==NULL"); 01181 ERROR2IF(Verb!=PT_LINETO && Verb!=PT_MOVETO,FALSE,"ProcessPathDistance::NewPoint() - unknown path verb"); 01182 01183 01184 if (!Found && !ProcFirstPoint && Verb==PT_LINETO) 01185 { 01186 double dx=pCoord->x-PrevCoord.x; 01187 double dy=pCoord->y-PrevCoord.y; 01188 double LineLength=sqrt(dx*dx+dy*dy); 01189 01190 double NextDist=CurrentDist+LineLength; 01191 01192 m_LastFoundDistance = CurrentDist; 01193 //TRACEUSER( "Diccon", _T("m_LastFound = %f\n"), m_LastFoundDistance); 01194 if (NextDist>=DesiredDist) 01195 { 01196 if (LineLength>0) 01197 { 01198 double FractOfLine = (DesiredDist-CurrentDist)/LineLength; 01199 double x = PrevCoord.x+dx*FractOfLine; 01200 double y = PrevCoord.y+dy*FractOfLine; 01201 CoordAtDist = DocCoord((MILLIPOINT)x,(MILLIPOINT)y); 01202 TangentAtDist = atan2(dy,dx); 01203 01204 } 01205 else 01206 { 01207 CoordAtDist = PrevCoord; 01208 TangentAtDist = 0; 01209 } 01210 Found=TRUE; 01211 } 01212 01213 CurrentDist=NextDist; 01214 } 01215 01216 PrevCoord=*pCoord; 01217 01218 return TRUE; 01219 } 01220 01221 /****************************************************************************************** 01222 > BOOL ProcessPathDistance::NewPoint(PathVerb Verb, DocCoord* pCoord) 01223 01224 Author: Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com> 01225 Created: 9/4/95 01226 Inputs: Verb - current point verb (only processes PT_LINETO) 01227 pCoord - current point coords 01228 Returns: TRUE 01229 Purpose: Called from ProcessPath which has generated a new point on the open element. 01230 If the length of this line causes the cummulaive length to exceed the 01231 desired length, get the tangent of this line then use the remaing distance 01232 (Desired-Current) to linearly interpolate to the desired coord on the line 01233 ******************************************************************************************/ 01234 01235 BOOL ProcessPathDistance::NewPointA(PathVerb Verb, DocCoord* pCoord, UINT32* pPressure) 01236 { 01237 ERROR2IF(pCoord==NULL,FALSE,"ProcessPathDistance::NewPoint() - pCoord==NULL"); 01238 ERROR2IF(Verb!=PT_LINETO && Verb!=PT_MOVETO,FALSE,"ProcessPathDistance::NewPoint() - unknown path verb"); 01239 01240 01241 if (!Found && !ProcFirstPoint && Verb==PT_LINETO) 01242 { 01243 double dx=pCoord->x-PrevCoord.x; 01244 double dy=pCoord->y-PrevCoord.y; 01245 double LineLength=sqrt(dx*dx+dy*dy); 01246 01247 double NextDist=CurrentDist+LineLength; 01248 01249 m_LastFoundDistance = CurrentDist; 01250 //TRACEUSER( "Diccon", _T("m_LastFound = %f\n"), m_LastFoundDistance); 01251 if (NextDist>=DesiredDist) 01252 { 01253 if (LineLength>0) 01254 { 01255 double FractOfLine = (DesiredDist-CurrentDist)/LineLength; 01256 double x = PrevCoord.x+dx*FractOfLine; 01257 double y = PrevCoord.y+dy*FractOfLine; 01258 CoordAtDist = DocCoord((MILLIPOINT)x,(MILLIPOINT)y); 01259 TangentAtDist = atan2(dy,dx); 01260 if (pPressure != NULL) 01261 PressureAtDist = (UINT32)((*pPressure * (1-FractOfLine)) + (m_PrevPressure * FractOfLine)); 01262 } 01263 else 01264 { 01265 CoordAtDist = PrevCoord; 01266 TangentAtDist = 0; 01267 if (pPressure != NULL) 01268 PressureAtDist = m_PrevPressure; 01269 } 01270 Found=TRUE; 01271 } 01272 01273 CurrentDist=NextDist; 01274 } 01275 01276 PrevCoord=*pCoord; 01277 m_PrevPressure = *pPressure; 01278 return TRUE; 01279 } 01280 01281 01282 /****************************************************************************************** 01283 01284 > INT32 ProcesPathDistance::Process(const ProcessFlags& PFlags, INT32 AlreadyProcessed) 01285 01286 Inputs: PFlags = Flags to direct the action of this function 01287 AlreadyProcessed - the number of coordinates already processed 01288 Outputs: 01289 Returns: The number of coordinates processed (in total) or -1 for failure 01290 01291 Purpose: Processes a path. It will scan through the elements of a path, passing 01292 points to a NewPoint virtual function. It will also flatten curves if 01293 found and pass the generated points on as well. 01294 01295 Quantise a path to an output path. The output path may already contain 01296 data, if so the quantised data will be added on the end. 01297 If the output path points to 'this' path, then having successfully quantised 01298 to the end of the output path, the original data in the buffer will be 01299 removed. This allows you to quantise a path to itself. 01300 If the routine fails, all quantisation data so far created by the routine 01301 will be removed. 01302 01303 This variant only processes coordinates after AlreadyProcessed 01304 01305 ******************************************************************************************/ 01306 01307 INT32 ProcessPathDistance::Process(const ProcessFlags& PFlags, INT32 AlreadyProcessed) 01308 { 01309 01310 // The idea here is that we create a quantised path. This means we 01311 // scan through the path descretizing curves and lines dependent 01312 // on the flatness value given. 01313 01314 DocCoord* ICoords = ProcSource->GetCoordArray(); 01315 PathVerb* IVerbs = ProcSource->GetVerbArray(); 01316 01317 UINT32* IPressure = NULL; 01318 if (ProcSource->HasWidth()) 01319 IPressure = ProcSource->GetWidthArray(); 01320 01321 //if (IPressure == NULL) 01322 // ERROR3("No pressure array"); 01323 01324 INT32 numinsource = ProcSource->GetNumCoords(); 01325 01326 INT32 i=AlreadyProcessed; 01327 BOOL ok = TRUE; 01328 if ( i > 0) 01329 { 01330 ProcFirstPoint = FALSE; 01331 } 01332 01333 // scan through the input verbs 01334 while ((i < numinsource) && (ok) && (!Found)) 01335 { 01336 // if (IPressure != NULL) 01337 // TRACEUSER( "Diccon", _T("PathProc Pressure = %d\n"), IPressure[i]); 01338 switch (IVerbs[i] & ~PT_CLOSEFIGURE) 01339 { 01340 case PT_MOVETO: 01341 OpenElement(PT_MOVETO, i); 01342 if (IPressure != NULL) 01343 ok = NewPointA(PT_MOVETO, &ICoords[i], &IPressure[i]); 01344 else 01345 ok = NewPoint(PT_MOVETO, &ICoords[i]); 01346 01347 if (CloseElement(ok, PT_MOVETO, i)) 01348 i=(numinsource-1); 01349 break; 01350 01351 case PT_LINETO: 01352 { 01353 BOOL IsCloseFigure = ((IVerbs[i] & PT_CLOSEFIGURE) != 0); // Remember if this is the closing element 01354 01355 OpenElement(PT_LINETO, i); 01356 if (!PFlags.QuantiseAll) 01357 { 01358 if (!PFlags.QuantiseLines) 01359 if (IPressure != NULL) 01360 ok = NewPointA(PT_LINETO, &ICoords[i], &IPressure[i]); 01361 else 01362 ok = NewPoint(PT_LINETO, &ICoords[i]); 01363 else 01364 { 01365 DocCoord End = ICoords[i]; 01366 for (double mu = 0.2; (mu<1.2) && ok; mu+=0.2 ) 01367 { 01368 DocCoord dest; 01369 dest.x = (INT32)((1-mu)*ProcPreviousEl.x + mu*End.x); 01370 dest.y = (INT32)((1-mu)*ProcPreviousEl.y + mu*End.y); 01371 ok = NewPoint(PT_LINETO, &dest); 01372 } 01373 } 01374 } 01375 else 01376 { 01377 ok = InsertQuantisedLineTo(&ICoords[i], &ProcPreviousEl); 01378 } 01379 if (CloseElement(ok, PT_LINETO, i)) 01380 i=(numinsource-1); 01381 else if (IsCloseFigure) // If continuing, and this is the end of a closed figure 01382 CloseFigure(); // then close it off 01383 } 01384 break; 01385 01386 case PT_BEZIERTO: 01387 { 01388 BOOL IsCloseFigure = ((IVerbs[i+2] & PT_CLOSEFIGURE) != 0); // Remember if this is the closing element 01389 01390 OpenElement(PT_BEZIERTO, i); 01391 if (!PFlags.FlattenCurves) 01392 ok = NewPoint(PT_BEZIERTO, &ICoords[i]); 01393 else 01394 { 01395 ok = FlattenCurve(ProcPreviousEl.x, ProcPreviousEl.y, 01396 ICoords[i].x, ICoords[i].y, 01397 ICoords[i+1].x, ICoords[i+1].y, 01398 ICoords[i+2].x, ICoords[i+2].y, (PFlags.QuantiseAll) ); 01399 } 01400 if (CloseElement(ok, PT_BEZIERTO, i)) 01401 i=(numinsource-1); 01402 else 01403 { 01404 if (IsCloseFigure) // If continuing, and this is the end of a closed figure 01405 CloseFigure(); // then close it off 01406 01407 i+=2; 01408 } 01409 } 01410 break; 01411 01412 default: ERROR3("ProcessPath::Process() - unknown path verb!"); 01413 01414 } 01415 ICoords = ProcSource->GetCoordArray(); 01416 IVerbs = ProcSource->GetVerbArray(); 01417 i++; 01418 ProcFirstPoint = FALSE; 01419 ProcPreviousEl = ICoords[i-1]; 01420 } 01421 01422 // we are recording the point previous to the one we just found. 01423 // i represents the next point, i-1 is the point we just found, so 01424 // the one before that is i-2 01425 if (Found) 01426 m_LastFoundIndex = i -2; 01427 01428 INT32 ReturnValue; 01429 // we have processed i-1 points 01430 if (ok) 01431 ReturnValue = i-1; 01432 else 01433 ReturnValue = -1; 01434 01435 return ok; 01436 }