tracectl.cpp

Go to the documentation of this file.
00001 // $Id: tracectl.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 // Tracer control class
00099 
00100 /*
00101 */
00102 
00103 #include "camtypes.h"
00104 #include "tracectl.h"
00105 #include "tracergn.h"
00106 
00107 //#include "ccobject.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 
00109 //#include "bitmap.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00110 //#include "nodebmp.h"
00111 #include "bitmpinf.h"
00112 #include "bfxalu.h"
00113 #include "bfxpixop.h"
00114 #include "nodepath.h"
00115 #include "lineattr.h"
00116 //#include "group.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00117 //#include "fillval.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00118 #include "oilprog.h"
00119 //#include "andy.h"
00120 //#include "fillattr.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00121 #include "fitcurve.h"
00122 #include "pathproc.h"
00123 #include "progress.h"
00124 //#include "tracerc.h"
00125 #include "keypress.h"
00126 
00127 // This is not compulsory, but you may as well put it in so that the correct version
00128 // of your file can be registered in the .exe
00129 DECLARE_SOURCE("$Revision: 1282 $");
00130 
00131 // An implement to match the Declare in the .h file.
00132 // If you have many classes, it is recommended to place them all together, here at the start of the file
00133 CC_IMPLEMENT_DYNCREATE(TraceControl, BitmapEffectBase)
00134 
00135 // This will get Camelot to display the filename and linenumber of any memory allocations
00136 // that are not released at program exit
00137 #define new CAM_DEBUG_NEW
00138 
00139 #define TRACEUSESTATS 0
00140 
00141 const INT32 MARKED_PIXEL = 0xFFFFFFFF;
00142 const INT32 CLEAR_PIXEL = 0xFF808080;
00143 const INT32 REGION_PIXEL = 0xFF000000;
00144 const INT32 BIT_SCANCOLOUR = 0x80000000;
00145 const INT32 BIT_THRESHOLD = 0x40000000;
00146 const INT32 BIT_CACHES_THRESHOLD = 0x01000000;
00147 const INT32 BIT_CACHEV_THRESHOLD = 0x02000000;
00148 const INT32 BIT_CACHES_COLOURTHRESHOLD = 0x04000000;
00149 const INT32 BIT_CACHEV_COLOURTHRESHOLD = 0x08000000;
00150 const INT32 BIT_CACHES_POSITIVE = 0x10000000;
00151 const INT32 BIT_CACHEV_POSITIVE = 0x20000000;
00152 
00153 #ifdef _DEBUG
00154 #define SetDebugBitmap(n,b) { if (DebugSwitch[n]) { if (!pDebug[n]) pDebug[n]=ALU->NewBitmap(pUndithered,0,0,32); \
00155                             DebugInvalid[n]=TRUE;\
00156                             if (pDebug[n]) { ALU->SetA(pDebug[n]); if (b) {ALU->SetB(b); ALU->ByteCopyBA();} \
00157                             else ALU->ZeroA(); } } }
00158 #else
00159 #define SetDebugBitmap(n,b) { if (FALSE); }
00160 #endif
00161 
00162 /*******************************************************************************************
00163 
00164 >   TraceControl::TraceControl() : CCObject()
00165 
00166     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00167     Created:    14/12/94
00168     Purpose:    Constructs the trace control object
00169 
00170 *******************************************************************************************/
00171 
00172 TraceControl::TraceControl() : BitmapEffectBase()
00173 {
00174     pOriginal = NULL;
00175     pProposed = NULL;
00176     pUndithered = NULL;
00177     pCurrentPath = NULL;
00178     pFill = NULL;
00179     pTraceRegion = NULL;
00180     pStats = NULL;
00181     pErrorRegionList = NULL;
00182     pThresholdPixelOp = NULL;
00183     pColourThresholdPixelOp = NULL;
00184     pPositivePixelOp = NULL;
00185 
00186     pTree=NULL;
00187     pJoinNode=NULL;
00188 
00189 #ifdef _DEBUG
00190     for (INT32 i=0; i<NUM_TRACECTL_DEBUG_BITMAPS; i++) {pDebug[i]=NULL;DebugSwitch[i]=FALSE;DebugInvalid[i]=TRUE;}
00191 #endif
00192 
00193     MaximumInitialAreaErrorThreshold = 0.12;
00194     InitialAreaErrorThreshold = MaximumInitialAreaErrorThreshold;
00195     MinimumInitialAreaErrorThreshold = 0.06;
00196     InitialAreaErrorRatio = 0.5;
00197 
00198     GradFillError = 1.0;
00199     NewGradFillError = 0.0;
00200     MinGradFillError = 2.0/256.0;
00201     GradFillErrorRatio = 0.8;
00202 
00203     MinPixelError=0.45;
00204     MaxPixelError=2.0;
00205     PixelError=MaxPixelError;
00206     PixelErrorRatio=0.5;
00207     QuantColours=30;
00208 
00209     Blur=64.0;
00210     Smooth=0.0;
00211     Log2BPP=5;
00212     Method = TRACEMETHOD_TRUECOL;
00213 
00214     MinimumArea = 10;
00215 
00216     FoundRegion = FALSE;
00217     InitialX = 0 ;
00218     InitialY = 0;
00219 
00220     ScanPointX = 0;
00221     ScanPointY = 0;
00222 
00223     XSize = 0;
00224     YSize = 0;
00225 
00226     HavePath = FALSE;
00227 
00228     TotalPasses=0;
00229     NumPasses=0;
00230     NumPaths=0;
00231     NumCusps=0;
00232     NumPoints=0;
00233     ProgressDone=FALSE;
00234 
00235     InitBitmap();
00236 
00237     FirstShape = TRUE;
00238     ShapeFreePass = FALSE;
00239 }       
00240 
00241 
00242 
00243 /*******************************************************************************************
00244 
00245 >   TraceControl::~TraceControl()
00246 
00247     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00248     Created:    14/12/94
00249     Purpose:    Destructor, does nothing
00250 
00251 *******************************************************************************************/
00252 
00253 TraceControl::~TraceControl()
00254 {
00255     InitBitmap(); // Free bitmaps if there are any
00256     RemoveTree();
00257     if (pTraceRegion) delete pTraceRegion;
00258     if (pCurrentPath) delete pCurrentPath;
00259     if (pFill) delete pFill;
00260     if (pStats) delete pStats;
00261     if (pErrorRegionList) delete pErrorRegionList;
00262     if (pThresholdPixelOp) delete pThresholdPixelOp;
00263     if (pColourThresholdPixelOp) delete pColourThresholdPixelOp;
00264     if (pPositivePixelOp) delete pPositivePixelOp;
00265 
00266 
00267 #ifdef _DEBUG
00268     for (INT32 i=0; i<NUM_TRACECTL_DEBUG_BITMAPS; i++) if (pDebug[i]) delete pDebug[i];
00269 #endif
00270 } 
00271 
00272 /********************************************************************************************
00273 
00274 >   BOOL TraceControl::GetParams(
00275         TraceMethod * pMethod = NULL,
00276         INT32 * pMinimumArea = NULL,
00277         double * pMaximumInitialAreaErrorThreshold = NULL,
00278         double * pMinimumInitialAreaErrorThreshold = NULL,
00279         double * pInitialAreaErrorRatio = NULL,
00280         double * pMinGradFillError = NULL,
00281         double * pGradFillErrorRatio = NULL,
00282         double * pMinPixelError = NULL,
00283         double * pMaxPixelError = NULL,
00284         double * pPixelErrorRatio = NULL,
00285         double * pQuantColours = NULL,
00286         double * pBlur = NULL,
00287         double * pSmooth = NULL
00288         );
00289 
00290     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00291     Created:    17/1/95
00292     Inputs:     None
00293     Outputs:    double values of parameters to read. May be set to NULL to not read them
00294     Returns:    TRUE on success, FALSE (& error set) on failure
00295     Purpose:    Gets the tracing parameters
00296     Errors:     mainly memory.
00297     Scope:      Public
00298     SeeAlso:    -
00299 
00300 ********************************************************************************************/
00301 
00302 BOOL TraceControl::GetParams(
00303         TraceMethod * pMethod,
00304         INT32 * pMinimumArea,
00305         double * pMaximumInitialAreaErrorThreshold,
00306         double * pMinimumInitialAreaErrorThreshold,
00307         double * pInitialAreaErrorRatio,
00308         double * pMinGradFillError,
00309         double * pGradFillErrorRatio,
00310         double * pMinPixelError,
00311         double * pMaxPixelError,
00312         double * pPixelErrorRatio,
00313         double * pQuantColours,
00314         double * pBlur,
00315         double * pSmooth
00316         )
00317 {
00318     if (pMethod)                            *pMethod                            =Method;
00319     if (pMinimumArea)                       *pMinimumArea                       =MinimumArea;
00320     if (pMaximumInitialAreaErrorThreshold)  *pMaximumInitialAreaErrorThreshold  =MaximumInitialAreaErrorThreshold;
00321     if (pMinimumInitialAreaErrorThreshold)  *pMinimumInitialAreaErrorThreshold  =MinimumInitialAreaErrorThreshold;
00322     if (pInitialAreaErrorRatio)             *pInitialAreaErrorRatio             =InitialAreaErrorRatio;
00323     if (pMinGradFillError)                  *pMinGradFillError                  =MinGradFillError;
00324     if (pGradFillErrorRatio)                *pGradFillErrorRatio                =GradFillErrorRatio;
00325     if (pMinPixelError)                     *pMinPixelError                     =MinPixelError;
00326     if (pMaxPixelError)                     *pMaxPixelError                     =MaxPixelError;
00327     if (pPixelErrorRatio)                   *pPixelErrorRatio                   =PixelErrorRatio;
00328     if (pQuantColours)                      *pQuantColours                      =QuantColours;
00329     if (pBlur)                              *pBlur                              =Blur;
00330     if (pSmooth)                            *pSmooth                            =Smooth;
00331     return TRUE;
00332 }
00333 
00334 /********************************************************************************************
00335 
00336 >   BOOL TraceControl::SetParams(
00337         TraceMethod * pMethod = NULL,
00338         INT32 * pMinimumArea = NULL,
00339         double * pMaximumInitialAreaErrorThreshold = NULL,
00340         double * pMinimumInitialAreaErrorThreshold = NULL,
00341         double * pInitialAreaErrorRatio = NULL,
00342         double * pMinGradFillError = NULL,
00343         double * pGradFillErrorRatio = NULL,
00344         double * pMinPixelError = NULL,
00345         double * pMaxPixelError = NULL,
00346         double * pPixelErrorRatio = NULL,
00347         double * pQuantColours = NULL,
00348         double * pBlur = NULL,
00349         double * pSmooth = NULL
00350         )
00351 
00352     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00353     Created:    17/1/95
00354     Inputs:     ^double values of parameters to set. May be set to NULL to not change them
00355     Outputs:    None
00356     Returns:    TRUE on success, FALSE (& error set) on failure
00357     Purpose:    Sets the tracing parameters
00358     Errors:     mainly memory.
00359     Scope:      Public
00360     SeeAlso:    -
00361 
00362 This call can only run after InitBitmaps() as some of the parameters live in the TraceRegion
00363 (yes, this is a bit messy)
00364 
00365 ********************************************************************************************/
00366 
00367 BOOL TraceControl::SetParams(
00368         TraceMethod * pMethod,
00369         INT32 * pMinimumArea,
00370         double * pMaximumInitialAreaErrorThreshold,
00371         double * pMinimumInitialAreaErrorThreshold,
00372         double * pInitialAreaErrorRatio,
00373         double * pMinGradFillError,
00374         double * pGradFillErrorRatio,
00375         double * pMinPixelError,
00376         double * pMaxPixelError,
00377         double * pPixelErrorRatio,
00378         double * pQuantColours,
00379         double * pBlur,
00380         double * pSmooth
00381         )
00382 {
00383     ERROR2IF((!pTraceRegion), FALSE, "SetParams() called without prior call to InitBitmaps()");
00384     if (pMethod)                            Method                              =*pMethod;
00385     if (pMinimumArea)                       MinimumArea                         =*pMinimumArea;
00386     if (pMaximumInitialAreaErrorThreshold)  MaximumInitialAreaErrorThreshold    =*pMaximumInitialAreaErrorThreshold;
00387     if (pMinimumInitialAreaErrorThreshold)  MinimumInitialAreaErrorThreshold    =*pMinimumInitialAreaErrorThreshold;
00388     if (pInitialAreaErrorRatio)             InitialAreaErrorRatio               =*pInitialAreaErrorRatio;
00389     if (pMinGradFillError)                  MinGradFillError                    =*pMinGradFillError;
00390     if (pGradFillErrorRatio)                GradFillErrorRatio                  =*pGradFillErrorRatio;
00391     if (pMinPixelError)                     MinPixelError                       =*pMinPixelError;
00392     if (pMaxPixelError)                     MaxPixelError                       =*pMaxPixelError;
00393     if (pPixelErrorRatio)                   PixelErrorRatio                     =*pPixelErrorRatio;
00394     if (pQuantColours)                      QuantColours                        =*pQuantColours;
00395     if (pBlur)                              Blur                                =*pBlur;
00396     if (pSmooth)                            Smooth                              =*pSmooth;
00397     return TRUE;
00398 }
00399 
00400 
00401 /********************************************************************************************
00402 
00403 >   BOOL TraceControl::InitBitmap( KernelBitmap * theOriginal = NULL);
00404                     
00405     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00406     Created:    17/1/95
00407     Inputs:     theOriginal = pointer to the bitmap to use as the original to trace
00408                            or NULL to cancel use of bitmap
00409     Outputs:    theProposed = pointer to a place to store a pointer to the proposed image
00410                            we'll be using. May be NULL if no record required of this.
00411                 theTemp     = pointer to a place to store a pointer to the temp image
00412                            we'll be using. May be NULL if no record required of this.
00413     Returns:    TRUE on success, FALSE (& error set) on failure
00414     Purpose:    Initialises trace control object to work on a given set of bitmaps
00415     Errors:     mainly memory.
00416     Scope:      Public
00417     SeeAlso:    -
00418 
00419 Also, if we don't have a traceregion or a grad fill we claim these.
00420 
00421 ********************************************************************************************/
00422 
00423 BOOL TraceControl::InitBitmap( KernelBitmap * theOriginal)
00424 {
00425 #ifdef _DEBUG
00426     for (INT32 i=0; i<NUM_TRACECTL_DEBUG_BITMAPS; i++) if (pDebug[i]) {delete pDebug[i];pDebug[i]=NULL;DebugInvalid[i]=TRUE;}
00427 #endif
00428 
00429     if (pErrorRegionList)
00430     {
00431         // We don't want this around
00432         delete pErrorRegionList;
00433         pErrorRegionList = NULL;
00434     }
00435 
00436     if (pThresholdPixelOp) delete pThresholdPixelOp;
00437     if (pColourThresholdPixelOp) delete pColourThresholdPixelOp;
00438     if (pPositivePixelOp) delete pPositivePixelOp;
00439     pThresholdPixelOp = NULL;
00440     pColourThresholdPixelOp = NULL;
00441     pPositivePixelOp = NULL;
00442 
00443     XSize = 0;
00444     YSize = 0;
00445 
00446     if (!pTraceRegion) if ((pTraceRegion /*assign*/ = new TraceRegion) == NULL) return FALSE;
00447     if (!pFill) if ((pFill /*assign*/ = new LinearFillAttribute) == NULL) return FALSE;
00448 
00449     if (!theOriginal) // They've asked us not to use this bitmap after all
00450     {
00451         // if we have a proposed copy, delete it
00452         if (pProposed) delete pProposed;
00453         if (pUndithered) delete pUndithered;
00454 
00455         pProposed = NULL;
00456         pUndithered = NULL;
00457 
00458         // record no original
00459         pOriginal = NULL;
00460         return TRUE;    // We succeeded
00461     }
00462     // if we have a proposed copy, delete it
00463     if (pProposed) delete pProposed;
00464     if (pUndithered) delete pUndithered;
00465 
00466     if (!RemoveTree(TRUE)) return FALSE;
00467     ProgressDone=0;
00468 
00469     pProposed = NULL;
00470     pUndithered = NULL;
00471 
00472     // Make up some pixel ops - if any memory allocs fail pOriginal will be NULL still
00473     if (Method == TRACEMETHOD_TRUECOL)
00474     {
00475         if ((pThresholdPixelOp = /*assign*/ new BfxThresholdPixelOp) ==NULL) return FALSE;
00476         if ((pColourThresholdPixelOp = /*assign*/ new BfxColourThresholdPixelOp) ==NULL) return FALSE;
00477         if ((pPositivePixelOp = /*assign*/ new /*BfxPositivePixelOp*/BfxColourThresholdPixelOp) ==NULL) return FALSE;
00478     }
00479     else
00480     {
00481         if ((pThresholdPixelOp = /*assign*/ new BfxThresholdPixelOpPseudo) ==NULL) return FALSE;
00482         if ((pColourThresholdPixelOp = /*assign*/ new BfxColourThresholdPixelOpPseudo) ==NULL) return FALSE;
00483         if ((pPositivePixelOp = /*assign*/ new /*BfxPositivePixelOp*/BfxColourThresholdPixelOpPseudo) ==NULL) return FALSE;
00484     }
00485 
00486 
00487     // Record for us
00488     pOriginal = theOriginal;
00489 
00490     FirstShape = TRUE;
00491 
00492     return TRUE; 
00493 }
00494 
00495 /********************************************************************************************
00496 
00497 >   BOOL TraceControl::RemoveTree(BOOL DeleteIt = TRUE)
00498                     
00499     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00500     Created:    17/1/95
00501     Inputs:     DeleteIt = TRUE to delete the tree, FALSE to merely disclaim responsibility for it
00502     Outputs:    None
00503     Returns:    TRUE on success, FALSE (& error set) on failure
00504     Purpose:    Relinquishes control of the tree structure
00505     Errors:     mainly memory.
00506     Scope:      Public
00507     SeeAlso:    -
00508 
00509 This call would be called with TRUE to delete the tree for instance on destruction of the object
00510 or if the trace was cancelled, but with FALSE if the tree was inserted into a doc.
00511 
00512 This call does nothing if the tree isn't there
00513 
00514 ********************************************************************************************/
00515 
00516 BOOL TraceControl::RemoveTree(BOOL DeleteIt)    
00517 {
00518     if (!DeleteIt) {pTree = NULL; pJoinNode=NULL; return TRUE;}
00519 
00520     if (pTree)
00521     {
00522         Node * pFirstChild = pTree->FindFirstChild();
00523         if (pFirstChild) pTree->DeleteChildren(pFirstChild);
00524         delete pTree;
00525         pTree = NULL;
00526         pJoinNode = NULL;
00527     }
00528     return TRUE;
00529 }
00530 
00531 /********************************************************************************************
00532 
00533 >   BOOL TraceControl::GetBitmaps( KernelBitmap * * theOriginal = NULL,
00534                                     KernelBitmap * * theProposed = NULL,
00535                                     KernelBitmap * * theUndithered = NULL   )
00536                     
00537     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00538     Created:    17/1/95
00539     Inputs:     None
00540     Outputs:    theOriginal = pointer to a place to store a pointer to the original to trace
00541                            we'll be using. May be NULL if no record required of this.
00542                 theProposed = pointer to a place to store a pointer to the proposed image
00543                            we'll be using. May be NULL if no record required of this.
00544                 theTemp     = pointer to a place to store a pointer to the temp image
00545                            we'll be using. May be NULL if no record required of this.
00546     Returns:    TRUE on success, FALSE (& error set) on failure
00547     Purpose:    Returns the current bitmap pointers
00548     Errors:     None yet
00549     Scope:      Public
00550     SeeAlso:    -
00551 
00552 None the bitmap pointers may be NULL if not initialised yet (for instance if no tracing has
00553 yet been done).
00554 
00555 ********************************************************************************************/
00556 
00557 BOOL TraceControl::GetBitmaps( KernelBitmap * * theOriginal,
00558                                 KernelBitmap * * theProposed, KernelBitmap * * theUndithered)
00559 {
00560 
00561     if (theOriginal) *theOriginal = pOriginal;
00562     if (theProposed) *theProposed = pProposed;
00563     if (theUndithered) *theUndithered = pUndithered;
00564     return TRUE;
00565 }
00566 
00567 /********************************************************************************************
00568 
00569 >   BOOL TraceControl::Trace(BOOL * Done)
00570                     
00571     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00572     Created:    17/1/95
00573     Inputs:     None
00574     Outputs:    Done - pointer to BOOL to indicate completion
00575     Returns:    TRUE on success, FALSE (& error set) on failure
00576     Purpose:    Spits out a single object into the trace output stream
00577     Errors:     Many possible
00578     Scope:      Public
00579     SeeAlso:    -
00580 
00581 This is the central routine that actually orchestrates tracing of a single object. Note that
00582 a return of FALSE indicates an error condition (and tracing should be abandonned). Successful
00583 completion is indicated by the setting of the Done flag. It is guaranteed that (a) the Done
00584 flag will be either cleared or set (unless you are silly enough to pass a Null pointer in 0
00585 in which case you wouldn't be able to check it anyway), and (b) the Done flag will be clear
00586 if an error condition occurs. Thus Done ALWAYS indicates successful completion.
00587 
00588 ********************************************************************************************/
00589 
00590 BOOL TraceControl::Trace(BOOL * Done)
00591 {
00592     // First set done flag to false after checking it exists. This way all
00593     // exits will be clean.
00594     ERROR2IF(!Done, FALSE, "Don't call TraceControl::Trace with a NULL Done ptr");
00595     *Done = FALSE;
00596 
00597     ERROR2IF((!pOriginal), FALSE, "Don't call TraceControl::Trace without calling InitBitmaps() first");
00598 
00599     // Welcome to control algorithm No.2. Hopefully this one won't turn out exponential.
00600     //
00601     // Minor introduction to state storage:
00602     //
00603     // Various things about the state of tracing are stored across path generation. These are:
00604     //      InitialAreaErrorThreshold - this decreases monotonically throughout the trace
00605     //      ErrorRegionList - (see MarkInitialArea()) and it's information in top byte of ProposedImage
00606     //
00607     // No, OK it wasn't exponential, merely square. Now I allege we have an O(n) algorithm or at least
00608     // an O(n^(3/2)) one. Welcome to algorithm no. 3 and the world of the BfxPixelOp.
00609 
00610     // Do some stuff on the first call
00611     if (FirstShape)
00612     {
00613         if (!RemoveTree(TRUE)) return FALSE;
00614 
00615         if ((pTree = /*assign*/ new NodeGroup) ==NULL ) return FALSE;
00616         if ((pJoinNode = /*assign*/ new AttrStrokeColour(pTree, FIRSTCHILD)) == NULL) return FALSE;
00617         DocColour TheColour(COLOUR_NONE);
00618         ((AttrStrokeColour *)pJoinNode)->SetStartColour(&TheColour);
00619         NodePath * pRect;
00620         AttrFillGeometry * pRectCol;
00621         if (!(((pRect = /*assign*/ new NodePath(pJoinNode, NEXT))!=NULL) && pRect->SetUpPath(32, 32))) return FALSE;
00622         if (!(((pRectCol = /*assign*/ new AttrFlatColourFill(pRect, FIRSTCHILD))!=NULL))) return FALSE;
00623         pJoinNode=pRect;
00624     
00625         TRACEUSER( "Alex", _T("> Removing dither\n"));
00626         if (pProposed) delete pProposed;
00627         if (pUndithered) delete pUndithered;
00628 
00629         pProposed = NULL;
00630         pUndithered = NULL;
00631 
00632         ERROR2IF(!ALU, FALSE, "OK, where's the ALU gone?");
00633 
00634         if (!ALU->SetB(pOriginal)) return FALSE;
00635         INT32 NumColours = (INT32)(17.5+(255.0-17.0)*QuantColours);
00636         if (Method==TRACEMETHOD_GREYSCALE) NumColours = (INT32)(2.5+(255.0-2.0)*QuantColours);
00637         if (!ALU->RemoveDither(&pUndithered, (INT32)(Blur*2.55+0.5), NumColours, Method)) return FALSE;
00638         ERROR2IF(!pUndithered, FALSE, "How come remove dither failed to generate a KB without generating an error");
00639 
00640         EndSlowJob();
00641         String_64 ProcessMessage(_R(IDS_TRACEDLG_TRACING));
00642         BeginSlowJob(100, FALSE, &ProcessMessage);
00643 
00644         // Now we should go and claim proposed bitmap the size of the undithered one
00645         if ((pProposed = /*assign*/ ALU->NewBitmap(pUndithered,0,0/*,32*/)) == NULL)
00646         {
00647             delete pUndithered;
00648             pUndithered = NULL;
00649             return FALSE;
00650         }
00651 
00652         ALU->SetA(pProposed);
00653         ALU->ZeroA(0xFF);
00654 
00655         if (!ALU->GetSize(pUndithered, &XSize, &YSize)) return FALSE;
00656 
00657         if (!(
00658             pThresholdPixelOp->SetBitmap(pUndithered, BIT_CACHEV_THRESHOLD, BIT_CACHES_THRESHOLD, FALSE) &&
00659             pColourThresholdPixelOp->SetBitmap(pUndithered, BIT_CACHEV_COLOURTHRESHOLD, BIT_CACHES_COLOURTHRESHOLD, FALSE) &&
00660             pPositivePixelOp->SetBitmap(pUndithered, BIT_CACHEV_POSITIVE, BIT_CACHES_POSITIVE, FALSE) &&
00661 
00662             TRUE)) return FALSE;
00663 
00664         TRACEUSER( "Alex", _T("> First shape, here we go\n"));
00665         FirstShape = FALSE;
00666         ShapeFreePass = FALSE;
00667         InitialAreaErrorThreshold = MaximumInitialAreaErrorThreshold;
00668         GradFillError = 1.0;
00669         NewGradFillError = 0.0;
00670         if (!(
00671             pThresholdPixelOp->ClearEntireCache() &&
00672             pColourThresholdPixelOp->ClearEntireCache() &&
00673             pPositivePixelOp->ClearEntireCache() &&
00674             TRUE)) return FALSE;
00675         
00676         // set aux bitmaps up so we can start reading colours
00677         if (!pPositivePixelOp->SetAuxilliaryBitmaps(NULL, pProposed, pUndithered, 0, 0))
00678             return FALSE;
00679 
00680 
00681 #ifdef _DEBUG
00682         for (INT32 i=0; i<NUM_TRACECTL_DEBUG_BITMAPS; i++) if (pDebug[i]) {delete pDebug[i];pDebug[i]=NULL;DebugInvalid[i]=TRUE;}
00683 #endif
00684         SetDebugBitmap(0, pUndithered);
00685 
00686         TotalPasses=0;
00687         NumPasses=0;
00688         NumPaths=0;
00689         NumCusps=0;
00690         NumPoints=0;
00691         ProgressDone=0;
00692 
00693         double iaet=InitialAreaErrorThreshold;
00694         while (TRUE)
00695         {
00696 
00697             // This is the same loop we use
00698             if (iaet<=MinimumInitialAreaErrorThreshold)
00699                 iaet=MinimumInitialAreaErrorThreshold;
00700             TotalPasses++;
00701 
00702             if (iaet-1E-10<=MinimumInitialAreaErrorThreshold)
00703                 break;
00704             iaet *= InitialAreaErrorRatio;
00705         }
00706 
00707 
00708         // build a path
00709         pRect->InkPath.FindStartOfPath();
00710 
00711         // Start at bottom left corner
00712         pRect->InkPath.InsertMoveTo(DocCoord(0,0));
00713         pRect->InkPath.InsertLineTo(DocCoord(0,YSize<<8));
00714         pRect->InkPath.InsertLineTo(DocCoord(XSize<<8,YSize<<8));
00715         pRect->InkPath.InsertLineTo(DocCoord(XSize<<8,0));
00716         pRect->InkPath.InsertLineTo(DocCoord(0,0));
00717 
00718         // Close the path properly
00719         pRect->InkPath.CloseSubPath();
00720         pRect->InkPath.IsFilled = TRUE; // What lovely encapsulation & abstraction...
00721 
00722         // And give it a vaguely appropriate colour
00723         GFStartC = GFEndC = (DWORD)(pPositivePixelOp->ReadOriginalPixel(0, 0)) &0x00FFFFFF;
00724         INT32 R = 0;
00725         INT32 G = 0;
00726         INT32 B = 0;
00727         pPositivePixelOp->TranslateToRGB(GFStartC, pUndithered, &R, &G, &B);
00728         DocColour RectColour( R, G, B );
00729         GFStartX = 0;
00730         GFStartY = 0;
00731         GFEndX = XSize;
00732         GFEndY = YSize;
00733         pRectCol->SetStartColour(&RectColour);
00734         return PlotGradFill(TRUE, FALSE);
00735         // And next time do some more interesting shapes as FirstShape is FALSE
00736     }
00737 
00738     // Set proposed path to whole bitmap
00739     HavePath = FALSE;
00740 
00741     // There are two embedded exits from the main region finding loop - when we've found a beneficial region we
00742     // want to stick in the tree, and when we have decided the trace is complete.   
00743     while (TRUE)
00744     {
00745         ERROR1IF(KeyPress::IsEscapePressed(), FALSE, _R(IDS_ABORT));
00746 
00747         // Get the next error area out.
00748         // Occasionally (when there are no regions left in the error region list), this will result in a 
00749         // complete pass through the bitmap determining threshold error (and a recalculation of the threshold)
00750         // and the building up of a new error list. At the end we know that the temp bitmap is marked with
00751         // REGION_PIXEL
00752         if (!MarkInitialArea()) return FALSE;
00753 
00754         if (!FoundRegion)
00755         {
00756             // Wow! We've found *no* regions whose errors are greater than the Minimum threshold
00757             // error specified. This means (amazingly) we've done the trace!
00758             *Done = TRUE;
00759             return TRUE;
00760         }
00761 
00762         //TRACEUSER( "Alex", _T("Found Initial region at %d, %d, colour %x\n"),InitialX, InitialY, ScanPointColour);
00763 
00764 
00765         // We do a number of passes to refine the area. These consist of tracing the current region, finding the best
00766         // grad fill for it, and finding the region that grad fill positiviely affects. We must do at least two
00767         // passes.
00768         INT32 Passes = 0;
00769         BOOL UseColourThresholdPixelOp = TRUE;
00770         do
00771         {
00772             // InitialX & InitialY are set up. Our next step is to trace the region. We trace at first with
00773             // the minimum accuracy (i.e. the max PixelError) and reduce the accuracy until we have got a path
00774             // that works. Works means it has at least n% of the pixels of the original region.
00775             PixelError = MaxPixelError;
00776             BOOL RegionTraceable = FALSE;
00777             while ((PixelError>=MinPixelError) && !RegionTraceable)     
00778             {
00779                 if (!(
00780                     pTraceRegion->SetParams(&PixelError) &&
00781                     TracePath(UseColourThresholdPixelOp?pColourThresholdPixelOp:pPositivePixelOp) &&
00782                                                     // Trace region to path
00783                     CalculateStatistics() &&        // Calculate grad fill stats
00784                     TRUE)) return FALSE;
00785                 if (PixelError>MinPixelError)
00786                 {
00787                     PixelError *= PixelErrorRatio;
00788                     if (PixelError<MinPixelError) PixelError=MinPixelError;
00789                 } else PixelError=0.0; // Ensures loop terminates
00790                 RegionTraceable = (!pStats) || (pStats->N > 2); // Grrr with all these fancy pixel ops we can't get the area
00791                                                    // as it's not calculated yet. Oh well.
00792                 //( ((double)(pStats->N))/((double)RegionArea)>PixelAccuracyRatio );
00793             }
00794 
00795             UseColourThresholdPixelOp = FALSE;
00796 
00797             if (RegionTraceable)
00798             {
00799                 HavePath = TRUE;
00800 
00801                 // We have to plot the things twice at the moment to do the error calc until we've performed
00802                 // more GDraw mungery
00803                 if (!(
00804                     FormGradFill() &&               // Determine best grad fill
00805 //                  PlotGradFill(FALSE, FALSE) &&   // Plot proposed + grad fill to temp
00806                     TRUE)) return FALSE;
00807 /*
00808 We'll have to do this another way (like just do it on the cached area)
00809 
00810                 if (FoundRegion && (NewGradFillError >= GradFillError))
00811                 {
00812                     TRACEUSER( "Alex", _T("> This region doesn't reduce the error!\n"));
00813                     FoundRegion=FALSE; // We've gone seriously awry!
00814                 }
00815 */
00816                 INT32 theErrorThreshold = (INT32)(0.5+3.0*DoubleSquare(InitialAreaErrorThreshold * 255.0));
00817                 if (!pPositivePixelOp->ClearCachedArea()) return FALSE;
00818                 // This is a bodge until we have a way to calculate the true grad fill colour
00819                 if (!pPositivePixelOp->SetAuxilliaryBitmaps(NULL, pProposed, pUndithered, theErrorThreshold,
00820                         GFStartC /*pPositivePixelOp->ReadOriginalPixel(InitialX, InitialY) &0x00FFFFFF */))
00821                     return FALSE;
00822 
00823                 // BODGE! We start in the middle and look around for somewhere helpful
00824                 FoundRegion = pPositivePixelOp->IsInRegion(InitialX, InitialY);
00825                 INT32 xadj;
00826                 INT32 yadj;
00827                 if (!FoundRegion) for (yadj=-1; (yadj<=1) && !FoundRegion; yadj++) 
00828                     for (xadj=-1; (xadj<=1) && !FoundRegion; xadj++)
00829                     if (pPositivePixelOp->IsInRegion(InitialX+xadj, InitialY+yadj))
00830                     {
00831                         FoundRegion=TRUE;
00832                         InitialX+=xadj;
00833                         InitialY+=yadj; // break done by setting FoundRegion as we can't do 2 level break
00834                     }
00835                         
00836                 // OK OK so this clears out the cache. We've lost a maximum of 9 pixels.
00837                 if (FoundRegion) if (!CheckMinimumArea(pPositivePixelOp)) return FALSE;
00838                 // Sets FoundRegion
00839                 RegionArea = MinimumArea + 1; // Bodge
00840 
00841                 // If we marked any points as OK
00842                 if (FoundRegion)
00843                 {
00844                     // Is the current path & grad fill good enough for us?
00845                     // We must have done at least one top to bottom and one top to here pass. If we have
00846                     // done the maximum number of passes that's OK too. Other than that, we continue refining
00847                     // if the rate of decent of error is looking good.
00848                     if (TRUE /*don't refine while we're not doing grad fills*/
00849                         || (Passes>=/*MaxRefinementPasses*/1) || ((Passes != 0) && !(FALSE /* some other loop criterion*/)))
00850                     {
00851                         
00852                         if (!PlotGradFill(TRUE, TRUE)) return FALSE;
00853                         if ((Smooth>3.0) && pCurrentPath)
00854                         {
00855 //                          if (!pCurrentPath->InkPath.Smooth(Smooth*(256.0*65536.0/100.0))) return FALSE;
00856 
00857                             INT32 orignumcoords = pCurrentPath->InkPath.GetNumCoords();
00858 
00859                             // create a path and quantise to it
00860                             Path QuantPath;
00861                             INT32 startpoints=((orignumcoords>24)?orignumcoords:24)*5;
00862                             QuantPath.Initialise(startpoints,(startpoints>2400)?2400:startpoints);
00863 
00864                             // quantise original path to QuantPath
00865                             //pCurrentPath->InkPath.Quantise(64.0, &QuantPath);
00866 
00867                             double coordsmooth = Smooth*10.24; /* Smooth/100.0*4.0*256.0; */
00868                             
00869                             ProcessFlags QuantFlags(TRUE,FALSE,TRUE);
00870                             pCurrentPath->InkPath.CreateFlatPath(QuantFlags, coordsmooth, &QuantPath);
00871 
00872                             // create and fit a smooth curve to the data points.
00873                             
00874                             // Full range up to 4 pixels out
00875                             CurveFitObject Smoothed(&QuantPath, coordsmooth*coordsmooth);
00876 
00877                             if (Smoothed.Initialise(&QuantPath,QuantPath.GetNumCoords()))
00878                             {
00879                                 Smoothed.FitCurve();
00880                                 QuantPath.CloseSubPath();
00881                                 QuantPath.IsFilled=TRUE;
00882 
00883                                 // now that we've smoothed the curve lets check on the number
00884                                 // of coordinates we've generated. If its more, then we should
00885                                 // leave the original path as it was. If its less then replace
00886                                 if (QuantPath.GetNumCoords()<orignumcoords)
00887                                     if (!pCurrentPath->InkPath.CloneFrom(QuantPath)) return FALSE;
00888         
00889                             }
00890                         }
00891 
00892                         ShapeFreePass=FALSE;
00893                         //if (pErrorRegionList) pErrorRegionList->Empty(); // This is a bodge to ensure reevaluation
00894                         GradFillError = NewGradFillError;
00895 
00896                         if (pCurrentPath) NumPoints+=pCurrentPath->InkPath.GetNumCoords()/3;
00897                         NumPaths++;
00898                         //TRACEUSER( "Alex", _T("> Inserting path covering %d points after %d refinement(s)\n\n"),pStats->N, Passes);
00899 
00900                         INT32 R = 0;
00901                         INT32 G = 0;
00902                         INT32 B = 0;
00903                         pPositivePixelOp->TranslateToRGB(GFStartC, pUndithered, &R, &G, &B);
00904                         DocColour TheColour( R, G, B );
00905 
00906                         AttrFillGeometry * pFillGeometry = new AttrFlatColourFill;
00907                         if (!pFillGeometry) return FALSE; //new sets error
00908                         
00909                         pFillGeometry->SetStartColour(&TheColour);
00910                         pFillGeometry->AttachNode(pCurrentPath, FIRSTCHILD);
00911 
00912                         // The first node has to be attached under pTree, the rest to the right
00913                         if (pJoinNode)
00914                         {
00915                             pCurrentPath->AttachNode(pJoinNode, NEXT);
00916                         }
00917                         else
00918                         {
00919                             pCurrentPath->AttachNode(pTree, FIRSTCHILD);
00920                         }
00921 
00922                         pJoinNode = pCurrentPath;
00923                         pCurrentPath = NULL;
00924 
00925                         return TRUE;
00926                     }
00927 
00928                     // We do a refinement
00929                 }
00930             }
00931             else
00932             {
00933                 FoundRegion = FALSE;                // OK, so technically we found a region, but as we can't find
00934                                                     // a path that encloses it, we might as well pretend we haven't...
00935             }
00936 
00937             Passes++;
00938         } while (FoundRegion);          // repeat refinement if pur region hasn't disappeared - else try next one
00939         TRACEUSER( "Alex", _T("< Rejecting malformed error region\n"));
00940         HavePath = FALSE;
00941     }
00942 
00943     
00944     // We should never get here
00945     ERROR3("OK, How come a while(TRUE) terminated? Has someone inserted a break or what?");
00946     return FALSE;
00947 }
00948 
00949 /*
00950 
00951 Here's the old ROD code:
00952 
00953         // Don't loop if we have a low enough grad fill error, or it is reducing slower than GradFillErrorRatio
00954     } while (((GradFillError > MinGradFillError) &&
00955             ( (PreviousGradFillError / GradFillError) > (1.0/GradFillErrorRatio)))
00956             || (PreviousGradFillError ==0.0 ));
00957 */
00958 
00959 /********************************************************************************************
00960 
00961 >   BOOL TraceControl::GetProgress(INT32 * pPercent = NULL,
00962                              INT32 * pNumPaths = NULL,
00963                              INT32 * pNumCusps = NULL,
00964                              INT32 * pNumPoints = NULL,
00965                              BOOL * pProgressDone = NULL)
00966                     
00967     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
00968     Created:    17/1/95
00969     Inputs:     Pointers to things to fill in
00970     Outputs:    *pPercent = percentage of way through trace
00971                 *pNumPaths = number of paths
00972                 *pNumCusps = number of cusps
00973                 *pNumPoints = number of points
00974                 *pProgressDone = TRUE if complete else false
00975     Returns:    TRUE on success, FALSE (& error set) on failure
00976     Purpose:    Returning information for status line function
00977     Errors:     None yet
00978     Scope:      Public
00979     SeeAlso:    None
00980 
00981 The pointers may be NULL if you're not interested in getting them filled in
00982 
00983 ********************************************************************************************/
00984 
00985 BOOL TraceControl::GetProgress(INT32 * pPercent,
00986                              INT32 * pNumPaths,
00987                              INT32 * pNumCusps,
00988                              INT32 * pNumPoints,
00989                              BOOL * pProgressDone)  
00990 {
00991     if (pProgressDone) *pProgressDone = ProgressDone && pOriginal;
00992     if (pPercent)
00993     {
00994         INT32 percent=ProgressDone?100:(INT32)(1.0+100.0*(
00995             ((double)ScanPointY/(double)(YSize?YSize:1)+(double)NumPasses)/(double)(TotalPasses?TotalPasses:1) ));
00996         if ((percent<0 ) || (!pOriginal) || (!ProgressDone && ScanPointX==0 && ScanPointY==0 && NumPasses==0)) percent=0;
00997         if (percent>100) percent=100;
00998         *pPercent=percent;
00999     }
01000     if (pNumPaths) *pNumPaths=NumPaths;
01001     if (pNumCusps) *pNumCusps=NumCusps;
01002     if (pNumPoints) *pNumPoints=NumPoints;
01003     return TRUE;
01004 }
01005 
01006 
01007 /********************************************************************************************
01008 
01009 >   BOOL TraceControl::CheckMinimumArea(BfxPixelOp * pBfxPixelOp)
01010                     
01011     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01012     Created:    17/1/95
01013     Inputs:     pBfxPixelOp = pointer to the pixel op to use
01014     Outputs:    None
01015     Returns:    TRUE on success, FALSE (& error set) on failure
01016     Purpose:    Determines whether atleast (MinimumArea) pixels are within the region
01017     Errors:     None yet
01018     Scope:      Public
01019     SeeAlso:    TraceControl::FloodSearch
01020 
01021 FoundRegion is set according the the result. The search starts at InitialX/InitialY
01022 
01023 This call *must* be done immediately (yes, immediately) after the cache is cleared. If not
01024 you lose all your caching. Har har.
01025 
01026 ********************************************************************************************/
01027 
01028 BOOL TraceControl::CheckMinimumArea(BfxPixelOp * pBfxPixelOp)
01029 {
01030     return pBfxPixelOp->CheckMinimumArea(MinimumArea, InitialX, InitialY, &FoundRegion);
01031 }
01032 
01033 /********************************************************************************************
01034 
01035 >   BOOL TraceControl::SetPath(NodePath * pNodePath)
01036                     
01037     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01038     Created:    17/1/95
01039     Inputs:     pNodePath = pointer to the NP to use or NULL for whole image
01040     Outputs:    None
01041     Returns:    TRUE on success, FALSE (& error set) on failure
01042     Purpose:    Sets up the NP to use
01043     Errors:     None yet
01044     Scope:      Public
01045     SeeAlso:    -
01046 
01047 It is the callers responsibility to deal with the old NP (in terms of memory management) if
01048 this call is used.
01049 
01050 ********************************************************************************************/
01051 
01052 BOOL TraceControl::SetPath(NodePath * pNodePath)
01053 {
01054     pCurrentPath = pNodePath;
01055     if (!pCurrentPath) HavePath = FALSE;
01056     return TRUE;
01057 }
01058 
01059 /********************************************************************************************
01060 
01061 >   NodePath * TraceControl::GetPaths()
01062                     
01063     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01064     Created:    17/1/95
01065     Inputs:     None
01066     Outputs:    None
01067     Returns:    ^CurrentPath or NULL if none
01068     Purpose:    Returns the current path
01069     Errors:     None yet
01070     Scope:      Public
01071     SeeAlso:    -
01072 
01073 ********************************************************************************************/
01074 
01075 Node * TraceControl::GetPaths()
01076 {
01077     return pTree;
01078 }
01079 
01080 /********************************************************************************************
01081 
01082 >   BOOL TraceControl::MarkInitialArea()
01083                     
01084     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01085     Created:    17/1/95
01086     Inputs:     None
01087     Outputs:    None
01088     Returns:    TRUE on success, FALSE (& error set) on failure
01089     Purpose:    Marks out intial area in temp bitmap
01090     Errors:     Many possible
01091     Scope:      Public
01092     SeeAlso:    -
01093 
01094 We find the next error region in the error region list and ensure that this is marked as
01095 REGION_PIXEL in the temporary bitmap. We do this by copying from the top byte of the
01096 Proposed bitmap if there are more regions on the list, otherwise we generate a new set of
01097 error regions in the following manner:
01098 
01099 The temporary bitmap is marked such that all those points whose squared errors exceed
01100 InitialAreaError^2 are set and all others cleared. Then BuildErrorList is called to build up
01101 the error list (well that's a surprise).
01102 
01103 Note we don't actually need the path for this as we can assume that the whole path is set,
01104 which is fair enough as the initial area will only be required when we haven't got a path.
01105 
01106 ********************************************************************************************/
01107 
01108 BOOL TraceControl::MarkInitialArea()
01109 {
01110     ERROR3IF (HavePath, "MarkInitialArea() called when a path was set up. Wierd...");
01111     ERROR3IF ((!pUndithered) || (!pProposed), "MarkInitialArea() missing some bitmaps");
01112 
01113     BOOL FirstCall = FALSE;
01114 
01115     if (!pErrorRegionList)
01116     {
01117         if ((pErrorRegionList = /*assign*/ new BfxErrorRegionList) == NULL) return FALSE;
01118         if (!pErrorRegionList->Init(1000))
01119         {
01120             delete pErrorRegionList;
01121             pErrorRegionList = NULL;
01122             return FALSE;
01123         }
01124         FirstCall = TRUE;
01125     }
01126 
01127     // What the main loop does: (just in case you were wondering)
01128     //
01129     // Tries to find something on the error region list
01130     // If it's now empty:
01131     //  tries the next scan point.
01132     //  (If the next scanpoint is off the end of the bitmap, resets it and tries again using a lower threshold,
01133     //   if it still can't find one, we're done)
01134     //  Marks regions of approximately that colour which form the new error region list (sorted by size)
01135     // Takes the next error region
01136     // Repeats until the next error region is greater or equal to 2 pixels in size.
01137     do
01138     {
01139 
01140         pErrorRegionList->Next(); // Move on to next one (doens't move if EOL)
01141         while (!pErrorRegionList->GetCurrent(&InitialX,&InitialY,&RegionArea)) // at end of list
01142         {
01143             // Go back to start
01144             pErrorRegionList->ResetRead();
01145 
01146             if (TRUE || ShapeFreePass || !pErrorRegionList->GetCurrent(&InitialX,&InitialY,&RegionArea)) // if no items on new list
01147             {
01148 //              double AError = 0.0;
01149 //              double BError = 0.0;
01150 //              INT32 TotalPixels = 0;
01151 //              INT32 MarkedPixels = 0;
01152 
01153                 INT32 theErrorThreshold = (INT32)(0.5+3.0*DoubleSquare(InitialAreaErrorThreshold * 255.0));
01154                 
01155 
01156                 // Find the next ScanPoint
01157                 BOOL FoundScanPoint=FALSE;
01158                 
01159                 do
01160                 {
01161                     // Don't look for one if we haven't done the very first area mark yet
01162                     if (!FirstCall)
01163                     {
01164                         theErrorThreshold = (INT32)(0.5+3.0*DoubleSquare(InitialAreaErrorThreshold * 255.0));
01165                         if (!(ALU->SetB(pProposed) && ALU->SetT(pUndithered))) return FALSE;
01166                         if (!(ALU->ScanThreshold(theErrorThreshold, &ScanPointX, &ScanPointY, NULL, &FoundScanPoint, TRUE))) return FALSE;
01167                     }
01168                                         
01169                     // If we haven't done the first area mark yet, or didn't find a point, we need to mark the area
01170                     if (FirstCall || !FoundScanPoint)
01171                     {
01172                         // Reset ScanPoint
01173                         ScanPointX=0;
01174                         ScanPointY=0;
01175                         
01176                         // Only on noninitial calls do we need to reduce the threshold
01177                         if (!FirstCall)
01178                         {
01179                             NumPasses++;
01180                             if (InitialAreaErrorThreshold-1E-10<=MinimumInitialAreaErrorThreshold)
01181                             {
01182                                 FoundRegion = FALSE; // We haven't & can't find an error region - so all done!
01183                                 ProgressDone=TRUE;
01184                                 return TRUE;         // OK though
01185                             }
01186                             InitialAreaErrorThreshold *= InitialAreaErrorRatio;
01187                         }
01188                         
01189                         // We're certainly not an initial call now
01190                         FirstCall=FALSE;
01191 
01192                         // Calculate new error threshold
01193                         if (InitialAreaErrorThreshold<=MinimumInitialAreaErrorThreshold)
01194                             InitialAreaErrorThreshold=MinimumInitialAreaErrorThreshold;
01195                         TRACEUSER( "Alex", _T("> Reducing InitialAreaErrorThreshold to %f\n"),InitialAreaErrorThreshold);
01196 
01197                     }               
01198                 } while (!FoundScanPoint);
01199 
01200                 // OK, we've found a ScanPoint to start off with. Hurrah. Now we take it's colour and build an ErrorRegion
01201                 // List based on that colour
01202 
01203                 // Clear the bit off, we don't want to deal with this pixel again unless it is remarked at a lower
01204                 // threshold. Note that if we actuially plot over this pixel, We later clear this bit for anything
01205                 // positively affected
01206                 //pUndithered->PlotPixel(ScanPointX,ScanPointY, pUndithered->ReadPixel(ScanPointX, ScanPointY) & ~BIT_THRESHOLD);
01207 
01208 
01209 
01210                 // Obtain the pixels colour
01211                 ScanPointColour =pPositivePixelOp->ReadOriginalPixel(ScanPointX, ScanPointY) & 0x00FFFFFF;              
01212 
01213 
01214                 // Now mark on thresholded error. What this means is we're marking all the pixels of a similar colour
01215                 // to the one which we've just found which are 'wrong' in the proposed bitmap as well. We'll use this
01216                 // as the first basis of our trace. We hope the area is large enough to give us a good approximation to
01217                 // a grad fill. This will hopefully extend over a larger area on the first refinement if (say) we've
01218                 // picked a grad filled band.
01219                 if (!pColourThresholdPixelOp->ClearCachedArea()) return FALSE;
01220                 if (!pColourThresholdPixelOp->SetAuxilliaryBitmaps(NULL, pProposed, pUndithered, theErrorThreshold, ScanPointColour))
01221                     return FALSE;
01222                 
01223                 // For the time being just insert the area we are using
01224                 InitialX=ScanPointX; InitialY=ScanPointY;
01225 
01226                 ScanPointX++;
01227                 if (ScanPointX>=XSize) {ScanPointX=0;ScanPointY++;} // we deliberately let this overrun
01228 
01229                 // Check minimum area & set FoundRegion
01230                 if (!CheckMinimumArea(pColourThresholdPixelOp)) return FALSE;
01231                 RegionArea = MinimumArea + 1; // Bodge
01232 
01233                 if (!pColourThresholdPixelOp->IsInRegion(InitialX, InitialY))
01234                 {
01235                     FoundRegion=FALSE;
01236 //                  ERROR3IF(IsUserName("Alex"),"ScanThreshold lied");
01237                 }
01238 
01239                 if (!pErrorRegionList->Empty()) return FALSE;
01240                 if ((FoundRegion) && (RegionArea>=MinimumArea)) if (!(pErrorRegionList->Insert(InitialX, InitialY, RegionArea))) return FALSE;
01241                 if (!(pErrorRegionList->Sort() && pErrorRegionList->ResetRead())) return FALSE; 
01242                 
01243             }
01244             // Mark begining of (as yet) shape free pass
01245             ShapeFreePass = TRUE;
01246         }
01247 
01248         // We've got one
01249         FoundRegion = TRUE;
01250 
01251     } while // validation - Loop if it's NOT (valid region area, AND this pixel set AND any adjacent pixel set)
01252         (!( (RegionArea>MinimumArea) &&
01253             (pColourThresholdPixelOp->IsInRegion(InitialX, InitialY)) &&
01254             ( // an adjacent pixel is set
01255                 pColourThresholdPixelOp->IsInRegion(InitialX-1, InitialY  ) ||
01256                 pColourThresholdPixelOp->IsInRegion(InitialX+1, InitialY  ) ||
01257                 pColourThresholdPixelOp->IsInRegion(InitialX,   InitialY-1) ||
01258                 pColourThresholdPixelOp->IsInRegion(InitialX-1, InitialY-1) ||
01259                 pColourThresholdPixelOp->IsInRegion(InitialX-1, InitialY-1) ||
01260                 pColourThresholdPixelOp->IsInRegion(InitialX,   InitialY+1) ||
01261                 pColourThresholdPixelOp->IsInRegion(InitialX-1, InitialY+1) ||
01262                 pColourThresholdPixelOp->IsInRegion(InitialX-1, InitialY+1) )
01263         ));
01264 
01265     return (pErrorRegionList->MarkUsed());
01266 }
01267 
01268 
01269 /********************************************************************************************
01270 
01271 >   BOOL TraceControl::TracePath(BfxPixelOp * pBfxPixelOp)
01272                     
01273     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01274     Created:    17/1/95
01275     Inputs:     None
01276     Outputs:    None
01277     Returns:    TRUE on success, FALSE (& error set) on failure
01278     Purpose:    A NodePath is traced from the temporary bitmap
01279     Errors:     Many possible
01280     Scope:      Public
01281     SeeAlso:    -
01282 
01283 The marked pixels from the temporary bitmap which are connected to Initial{X,Y} are turned
01284 into a NodePath which is then stored in CurrentPath.
01285 
01286 ********************************************************************************************/
01287 
01288 BOOL TraceControl::TracePath(BfxPixelOp * pBfxPixelOp)
01289 {
01290     if (!pCurrentPath)
01291         if (!(((pCurrentPath = /*assign*/ new NodePath)!=NULL) && pCurrentPath->SetUpPath(32, 32))) return FALSE;
01292     ERROR3IF ((!pUndithered) || (!pProposed) || (!pBfxPixelOp), "TracePath() missing some bitmaps");
01293 
01294     return( pTraceRegion->UseBitmap(pUndithered) &&
01295             pTraceRegion->UsePath(&(pCurrentPath->InkPath)) &&
01296             pTraceRegion->Trace(InitialX, InitialY, pBfxPixelOp) &&
01297             TRUE );
01298 }
01299 
01300 /********************************************************************************************
01301 
01302 >   BOOL TraceControl::CalculateStatistics()
01303                     
01304     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01305     Created:    17/1/95
01306     Inputs:     None
01307     Outputs:    None
01308     Returns:    TRUE on success, FALSE (& error set) on failure
01309     Purpose:    To determine the stats that help us find the optimum grad fill.
01310     Errors:     Many possible
01311     Scope:      Public
01312     SeeAlso:    -
01313 
01314 GDraw is called to plot the trace path in a way such that we obtain various useful stats.
01315 
01316 ********************************************************************************************/
01317 
01318 BOOL TraceControl::CalculateStatistics()
01319 {
01320 #if TRACEUSESTATS
01321     if (!pStats) if ((pStats = /*assign*/ new KernelStatistics) == NULL) return FALSE;
01322 
01323     ERROR3IF ((!pUndithered) || (!pProposed), "CalculateStatistics() missing some bitmaps");
01324     ERROR2IF ((!pCurrentPath), FALSE, "CalculateStatistics() called without path to grad fill"); 
01325     
01326     if (!(ALU->SetA(pUndithered))) return FALSE;
01327 
01328     //TRACEUSER( "Alex", _T("Calc stats\n"));
01329 
01330     return (ALU->GetStatistics(&(pCurrentPath->InkPath), pStats));
01331 #else
01332     return TRUE;
01333 #endif
01334 }
01335 
01336 /********************************************************************************************
01337 
01338 >   BOOL TraceControl::FormGradFill()
01339                     
01340     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01341     Created:    17/1/95
01342     Inputs:     None
01343     Outputs:    None
01344     Returns:    TRUE on success, FALSE (& error set) on failure
01345     Purpose:    Calculate the optimum grad fill from the stats available.
01346     Errors:     Many possible
01347     Scope:      Public
01348     SeeAlso:    -
01349                                                                                                     
01350 We do some cunning processing and end up with a grad fill attribute. We use the statistics
01351 from CalculateStatistics above.
01352 
01353 ********************************************************************************************/
01354 
01355 BOOL TraceControl::FormGradFill()
01356 {
01357     GFStartX = 0;
01358     GFStartY = 0;
01359     GFEndX = XSize;
01360     GFEndY = YSize;
01361 
01362 #if TRACEUSESTATS
01363     ERROR3IF((!pStats), "How come we got here without a statistics block then?!");
01364     INT32 R = (INT32)(pStats->R * 255.0);
01365     INT32 G = (INT32)(pStats->G * 255.0);
01366     INT32 B = (INT32)(pStats->B * 255.0);
01367 #if 0
01368 UINT32 pval = (UINT32)(pStats->Pixel);
01369 R = (pval/*>>0*/) & 0xFF; // Bitmaps are TRGB, colourrefs are TBGR
01370 G = (pval>>8) & 0xFF;
01371 B = (pval>>16) & 0xFF;
01372 #endif
01373 
01374     if (R<0) R=0;
01375     if (G<0) G=0;
01376     if (B<0) B=0;
01377     if (R>255) R=255;
01378     if (G>255) G=255;
01379     if (B>255) B=255;
01380 
01381     GFStartC = GFEndC = (DWORD)(R | (G<<8) | (B<<16));
01382 
01383     //TRACEUSER( "Alex", _T("Trying colour R=%d G=%d B=%d N=%d\n"),R,G,B,pStats->N);
01384 
01385     return TRUE;
01386 
01387 #else
01388 
01389     GFStartC = GFEndC = (DWORD)(pPositivePixelOp->ReadOriginalPixel(InitialX, InitialY)) &0x00FFFFFF;
01390     return TRUE;
01391 
01392 #endif
01393 }
01394 
01395 /********************************************************************************************
01396 
01397 >   BOOL TraceControl::PlotGradFill(BOOL ToProposed, BOOL UsePath = TRUE)
01398                     
01399     Author:     Alex_Bligh (Xara Group Ltd) <camelotdev@xara.com>
01400     Created:    17/1/95
01401     Inputs:     ToProposed set if to plot to Proposed rather than temp
01402                 UsePath = TRUE to plot path, FALSE to plot whole area
01403     Outputs:    None
01404     Returns:    TRUE on success, FALSE (& error set) on failure
01405     Purpose:    Plots the grad fill on top of the proposed bitmap into the temp bitmap
01406     Errors:     Many possible
01407     Scope:      Public
01408     SeeAlso:    -
01409 
01410 Pretty much a straight GDraw call or two.
01411 
01412 ********************************************************************************************/
01413 
01414 BOOL TraceControl::PlotGradFill(BOOL ToProposed, BOOL UsePath)
01415 {
01416     ERROR3IF ((!pUndithered) || (!pProposed) || (!ToProposed && !pUndithered), "PlotGradFill() missing some bitmaps");
01417     if (UsePath) ERROR2IF ((!pCurrentPath), FALSE, "PlotGradFill() called without path to grad fill"); 
01418 
01419     if (ToProposed)
01420     {
01421         if (!(ALU->SetA(pProposed))) return FALSE;
01422     }
01423     else
01424     {
01425         if (!(ALU->SetA(pUndithered) && ALU->SetB(pProposed) && ALU->ByteCopyBA())) return FALSE;
01426     }
01427 
01428     return (ALU->GradFillPath(UsePath?&(pCurrentPath->InkPath):NULL, GFStartC, GFEndC,
01429                               GFStartX, GFStartY, GFEndX, GFEndY, FALSE, TRUE));
01430 }
01431 
01432 
01433 

Generated on Sat Nov 10 03:47:12 2007 for Camelot by  doxygen 1.4.4