pathproc.cpp

Go to the documentation of this file.
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 }

Generated on Sat Nov 10 03:46:27 2007 for Camelot by  doxygen 1.4.4