samplist.cpp

Go to the documentation of this file.
00001 // $Id: samplist.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 
00099 // CSampleList and CSampleItem implementation
00100 
00101 #include "camtypes.h"
00102 #include "samplist.h"
00103 #include "brshcomp.h"
00104 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 #include "pen.h"
00106 
00107 CC_IMPLEMENT_DYNAMIC(CSampleItem, CCObject);
00108 CC_IMPLEMENT_DYNAMIC(CSampleData, CCObject);
00109 CC_IMPLEMENT_DYNAMIC(CDistanceSampler, CSampleData);
00110 
00111 const double MIN_COLLECTION_SAMPLE_RATE = 1.0;
00112 const double MAX_COLLECTION_SAMPLE_RATE = 1.0;
00113 const double MIN_RETRIEVAL_SAMPLE_RATE = 1.0;
00114 const double MAX_RETRIEVAL_SAMPLE_RATE = 10000.0;
00115 
00116 /*-------------------------------------------------------------------------------------------
00117 ------------------------------CSampleItem implementation-------------------------------------
00118 ---------------------------------------------------------------------------------------------
00119 */
00120 
00121 /********************************************************************************************
00122 
00123 >   CSampleItem::CSampleItem()
00124 
00125     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00126     Created:    31/5/2000
00127     Inputs:     -
00128     Outputs:    -
00129     Returns:    this object
00130     Purpose:    default constructor
00131                 
00132     Notes:      
00133 ********************************************************************************************/
00134 
00135 CSampleItem::CSampleItem()
00136 {
00137     m_Distance = 0;
00138     m_Coord.x = m_Coord.y = 0;
00139     m_Pressure = 0;
00140 }
00141 
00142 
00143 /********************************************************************************************
00144 
00145 >   CSampleItem::CSampleItem()
00146 
00147     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00148     Created:    31/5/2000
00149     Inputs:     Coord - the position of this sample
00150                 Distance - the distance along the path of this sample
00151     Outputs:    -
00152     Returns:    this object
00153     Purpose:    constructor with initialisation
00154                 
00155     Notes:      
00156 ********************************************************************************************/
00157 
00158 CSampleItem::CSampleItem(DocCoord Coord, MILLIPOINT Distance, UINT32 Pressure)
00159 {
00160     m_Coord = Coord;
00161     m_Distance = Distance;
00162     m_Pressure = Pressure;
00163 
00164 }
00165 
00166 
00167 /********************************************************************************************
00168 
00169 >   CSampleItem::CSampleItem()
00170 
00171     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00172     Created:    31/5/2000
00173     Inputs:     Other - another CSampleItem
00174     Outputs:    -
00175     Returns:    this object
00176     Purpose:    copy constructor
00177                 
00178     Notes:      
00179 ********************************************************************************************/
00180 
00181 CSampleItem::CSampleItem(const CSampleItem& Other)
00182 {
00183     m_Distance = Other.m_Distance;
00184     m_Coord    = Other.m_Coord;
00185     m_Pressure = Other.m_Pressure;
00186 
00187 }
00188 
00189 
00190 
00191 /********************************************************************************************
00192 
00193 >   CSampleItem CSampleItem::operator =(CSampleItem& Other)
00194 
00195     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00196     Created:    31/5/2000
00197     Inputs:     Other - another CSampleItem
00198     Outputs:    -
00199     Returns:    this object
00200     Purpose:    assignment operator
00201                 
00202     Notes:      
00203 ********************************************************************************************/
00204 
00205 CSampleItem CSampleItem::operator =(const CSampleItem& Other)
00206 {
00207     m_Coord    = Other.m_Coord;
00208     m_Distance = Other.m_Distance;
00209     m_Pressure = Other.m_Pressure;
00210     return *this;
00211 }
00212 
00213 
00214 
00215 /********************************************************************************************
00216 
00217 >   BOOL CSampleItem::operator ==(CSampleItem& Other)
00218 
00219     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00220     Created:    31/5/2000
00221     Inputs:     Other - another CSampleItem
00222     Outputs:    -
00223     Returns:    TRUE if the objects are identical, FALSE if they are not
00224     Purpose:    equality operator
00225                 
00226     Notes:      
00227 ********************************************************************************************/
00228 
00229 BOOL CSampleItem::operator ==(const CSampleItem& Other)
00230 {
00231     BOOL bDiff =  (m_Coord != Other.m_Coord || 
00232                    m_Distance != Other.m_Distance ||
00233                    m_Pressure != Other.m_Pressure);
00234     return bDiff;
00235 }
00236 
00237 /********************************************************************************************
00238 
00239 >   BOOL CSampleItem::operator ==(CSampleItem& Other)
00240 
00241     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00242     Created:    31/5/2000
00243     Inputs:     Other - another CSampleItem
00244     Outputs:    -
00245     Returns:    TRUE if the objects are identical, FALSE if they are not
00246     Purpose:    equality operator
00247                 
00248     Notes:      
00249 ********************************************************************************************/
00250 
00251 CSampleItem CSampleItem::InterpolateItems(CSampleItem& Other, double Proportion)
00252 {
00253     CSampleItem NewItem;
00254 
00255     if (Proportion < 0.0 || Proportion > 1.0)
00256     {
00257         ERROR3("Invalid proportion value in CSampleItem::InterpolateItems");
00258         return NewItem;
00259     }
00260 
00261     NewItem.m_Distance = (INT32)(((double)m_Distance * Proportion) + ((double)Other.m_Distance * (1-Proportion)));
00262     MILLIPOINT XVal = (INT32)((m_Coord.x * Proportion) + (Other.m_Coord.x * (1 - Proportion)));
00263     MILLIPOINT YVal = (INT32)((m_Coord.y * Proportion) + (Other.m_Coord.y * (1 - Proportion)));
00264     
00265     NewItem.m_Coord.x = XVal;
00266     NewItem.m_Coord.y = YVal;
00267     
00268     NewItem.m_Pressure = (UINT32)((m_Pressure * Proportion) + (Other.m_Pressure * (1-Proportion)));
00269 
00270     return NewItem;
00271 }
00272 
00273 /********************************************************************************************
00274 
00275 
00276 >   BOOL CSampleItem::WriteNative(CXaraFileRecord* pRecord)
00277 
00278     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00279     Created:    13/12/99
00280     Inputs:     pRecord - the record to write to
00281     Returns:    TRUE if the Node has written out a record to the filter
00282     Purpose:    Writes this sampledata item to a record
00283 
00284     SeeAlso:    CSampleData::WriteNative
00285 
00286 ********************************************************************************************/
00287 
00288 BOOL CSampleItem::WriteNative(CXaraFileRecord* pRecord)
00289 {
00290     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL in CSampleItem::WriteNative");
00291     
00292     BOOL ok = pRecord->WriteINT32((INT32)m_Pressure);
00293     if (ok) ok = pRecord->WriteCoord(m_Coord);
00294     if (ok) ok = pRecord->WriteINT32(m_Distance);
00295 
00296     return ok;
00297 }
00298 
00299 /*-------------------------------------------------------------------------------------------
00300 ------------------------------CSampleData implementation-------------------------------------
00301 ---------------------------------------------------------------------------------------------
00302 */
00303 
00304 /********************************************************************************************
00305 
00306 >   CSampleData::CSampleData()
00307 
00308     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00309     Created:    31/5/2000
00310     Inputs:     -
00311     Outputs:    -
00312     Returns:    this object
00313     Purpose:    default constructor
00314                 
00315     Notes:      
00316 ********************************************************************************************/
00317 
00318 CSampleData::CSampleData()
00319 {
00320     m_pSampleData = NULL;
00321     m_CollectionSampleRate = 1.0;
00322     m_RetrievalSampleRate  = 1.0;
00323     m_CollectionInternalIndex = 0;
00324     m_RetrievalInternalIndex  = 0;
00325     m_NumItems                = 0;
00326     m_MaxPressure             = 0;
00327     m_ElementSize = (UINT32)sizeof(CSampleItem);
00328 }
00329 
00330 
00331 /********************************************************************************************
00332 
00333 >   CSampleData::~CSampleData()
00334 
00335     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00336     Created:    31/5/2000
00337     Inputs:     -
00338     Outputs:    -
00339     Returns:    -
00340     Purpose:    destructor, cleans out the list
00341                 
00342     Notes:      
00343 ********************************************************************************************/
00344 
00345 CSampleData::~CSampleData()
00346 {
00347     if (m_pSampleData != NULL)
00348     {
00349         m_pSampleData->clear();
00350         delete m_pSampleData;
00351         m_pSampleData = NULL;
00352     }
00353 }
00354 
00355 
00356 /********************************************************************************************
00357 
00358 >   CSampleData* CSampleData::MakeCopy(CSampleData* pOther)
00359 
00360     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00361     Created:    31/5/2000
00362     Inputs:     -
00363     Outputs:    -
00364     Returns:    a copy of this object, unless something goes wrong (i.e memory) in which case NULL
00365     Purpose:    Makes a copy of this sample data.
00366                 
00367     Notes:      
00368 ********************************************************************************************/
00369 
00370 CSampleData* CSampleData::MakeCopy()
00371 {
00372     CSampleData* pNewData = new CSampleData;
00373 
00374     if (pNewData == NULL)
00375         return NULL;
00376 
00377     if (!pNewData->InitialiseData(m_NumItems))
00378     {
00379         delete pNewData;
00380         return NULL;
00381     }
00382 
00383     m_RetrievalSampleRate = 1; // make sure we get all the items
00384 
00385     CSampleItem TheItem;
00386 
00387     // unfortunately my implementation is a bit clumsy so we have to do the first item
00388     // by hand
00389     BOOL    Getok = GetAt(0, &TheItem);
00390     BOOL    Setok = pNewData->SetAt(0, TheItem);
00391     //TRACEUSER( "Diccon", _T("Copying pressure %d\n"), TheItem.m_Pressure);
00392     if (Getok == FALSE || Setok ==  FALSE)
00393         ERROR3("Failed to get or set first item in CSampleData::MakeCopy");
00394 
00395     UINT32 Counter = 1;
00396     // now we can loop through the rest
00397     while (Getok && Setok)
00398     {
00399         Getok = GetNext(&TheItem);
00400         Setok = pNewData->SetNext(TheItem);
00401         //TRACEUSER( "Diccon", _T("Copying pressure %d\n"), TheItem.m_Pressure);
00402         Counter++;
00403     }
00404 
00405     if (Counter != m_NumItems)
00406         TRACEUSER( "Diccon", _T("CSampleData::MakeCopy - Num items copied = %d, Actual num items = %d\n"), Counter, m_NumItems);
00407 
00408     return pNewData;
00409 }
00410 
00411 /********************************************************************************************
00412 
00413 >   BOOL CSampleData::InitialiseData(UINT32 Size, UINT32 GrowBy)
00414 
00415     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00416     Created:    31/5/2000
00417     Inputs:     -
00418     Outputs:    -
00419     Returns:    TRUE if we initialised ok, FALSE if we didn't get the memory
00420     Purpose:    creates the list member variable
00421                 
00422     Notes:      
00423 ********************************************************************************************/
00424 
00425 BOOL CSampleData::InitialiseData( size_t Size, UINT32 GrowBy )
00426 {
00427     // if we've already got a list then delete it
00428     if (m_pSampleData != NULL)
00429     {
00430         m_pSampleData->clear();
00431         delete m_pSampleData;
00432         m_pSampleData = NULL;
00433     }
00434     m_pSampleData = new SampleArray;
00435 
00436     if (m_pSampleData == NULL)
00437         return FALSE;
00438 
00439     if( Size < m_pSampleData->size() + GrowBy )
00440         Size = m_pSampleData->size() + GrowBy;
00441 
00442     m_pSampleData->resize( Size );
00443 
00444     return TRUE;
00445 }
00446 
00447 
00448 /********************************************************************************************
00449 
00450 >   BOOL CSampleData::CollectData(DocCoord Coord, UINT32 Pressure)
00451 
00452     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00453     Created:    31/5/2000
00454     Inputs:     Coord - the coordinate data
00455                 Pressure - the pressure data
00456     Outputs:    -
00457     Returns:    always TRUE in the base class
00458     Purpose:    This is the function you should override in you derived classes to do the sampling
00459                 with.  For an example see CDistanceSampler::CollectData
00460                 
00461     Notes:      
00462 ********************************************************************************************/
00463 
00464 BOOL CSampleData::CollectData(DocCoord Coord, UINT32 Pressure)
00465 {
00466     return TRUE;
00467 }
00468 
00469 /*-------------------------------------------------------------------------------------------
00470 -------------------------Array access functions-----------------------------------------------
00471 --------------------------------------------------------------------------------------------*/
00472 
00473 
00474 /********************************************************************************************
00475 
00476 >   void CSampleData::Add(CSampleItem& Item)
00477 
00478     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00479     Created:    31/5/2000
00480     Inputs:     Item - the item to insert
00481     Outputs:    -
00482     Returns:    -
00483     Purpose:    adds a new item to the end of the array
00484                 
00485     Notes:      
00486 ********************************************************************************************/
00487 
00488 void CSampleData::Add(CSampleItem& Item)
00489 {
00490     if (m_pSampleData != NULL)
00491         m_pSampleData->push_back(Item);
00492     m_NumItems++;
00493 
00494 }
00495 
00496 /********************************************************************************************
00497 
00498 >   BOOL CSampleData::SetAt(UINT32 Index CSampleItem& Item)
00499 
00500     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00501     Created:    31/5/2000
00502     Inputs:     Index - the position to set Item at
00503                 Item - the item to insert
00504     Outputs:    -
00505     Returns:    TRUE if successful, FALSE otherwise
00506     Purpose:    inserts Item at Index
00507                 
00508     Notes:      Currently it is not permitted to Set, Remove or Insert items if the sample rate is not 1.
00509                 This is because a) I really don't want people changing data in the array once
00510                 it has been collected (we're sampling remember) and b) Its a pain in the ass
00511 ********************************************************************************************/
00512 
00513 BOOL CSampleData::SetAt(UINT32 Index, CSampleItem& Item)
00514 {
00515     BOOL Retval = FALSE;
00516     if (m_pSampleData != NULL)
00517     {
00518         // we are not allowed to be setting data when the sample rate is not 1.0
00519         if (m_CollectionSampleRate < MIN_COLLECTION_SAMPLE_RATE || 
00520             m_CollectionSampleRate > MAX_COLLECTION_SAMPLE_RATE)
00521         {
00522             ERROR3("Attempting to set data when SampleRate != 1");
00523             return FALSE;
00524         }
00525         if (SetInternalCollectionIndex(Index))
00526         {
00527             (*m_pSampleData)[size_t(m_CollectionInternalIndex)] = Item; 
00528             Retval = TRUE;
00529             if ((UINT32)m_CollectionInternalIndex > m_NumItems)
00530                 m_NumItems = (UINT32)m_CollectionInternalIndex;
00531         }
00532         else
00533             ERROR3("Attempting to set over the end of the array in CSampleData::SetAt");
00534     }
00535     return Retval;
00536 }
00537 
00538 /********************************************************************************************
00539 
00540 >   BOOL CSampleData::SetNext(CSampleItem& Item, BOOL Grow)
00541 
00542     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00543     Created:    31/5/2000
00544     Inputs:     Item - the item to insert
00545                 Grow - do we wish to grow the array if we hit the end (defaults to FALSE)
00546     Outputs:    -
00547     Returns:    TRUE, unless we hit the end of the array and do not widh to grow
00548     Purpose:    Increments our internal index and then inserts a new item at that position.
00549                 If we hit the end of the array then we will add an element, so long as our flag
00550                 is set
00551     Notes:      
00552 ********************************************************************************************/
00553 
00554 BOOL CSampleData::SetNext(CSampleItem& Item, BOOL Grow)
00555 {
00556     BOOL Retval = FALSE;
00557     if (m_pSampleData != NULL)
00558     {
00559         // we are not allowed to be setting data when the sample rate is not 1.0
00560         if (m_CollectionSampleRate < MIN_COLLECTION_SAMPLE_RATE || 
00561             m_CollectionSampleRate > MAX_COLLECTION_SAMPLE_RATE)
00562         {
00563             ERROR3("Attempting to set data when SampleRate != 1");
00564             return FALSE;
00565         }
00566         if (IncrementInternalIndex(&m_CollectionInternalIndex))
00567         {
00568             // if internal index == -1 after incrementing it means we hit the end of the array
00569             if (m_CollectionInternalIndex != -1.0)
00570             {
00571                 //TRACEUSER( "Diccon", _T("Setting at %f\n"), m_CollectionInternalIndex);
00572                 (*m_pSampleData)[size_t(m_CollectionInternalIndex)] = Item;
00573                 Retval = TRUE;
00574                 if ((UINT32)m_CollectionInternalIndex > m_NumItems)
00575                     m_NumItems = (UINT32)m_CollectionInternalIndex;
00576             }
00577             else
00578             {
00579                 // we must have hit the end of the array, so we need to add
00580                 if (Grow == TRUE)
00581                 {
00582                     m_pSampleData->push_back( Item );
00583                     Retval = TRUE;
00584                     m_NumItems++;
00585                     m_CollectionInternalIndex = m_NumItems;
00586                 }
00587             }
00588         }
00589         else
00590             ERROR3("Failed to increment index in CSampleData::SetNext");
00591     }   
00592 
00593     return Retval;
00594 }
00595 
00596 /********************************************************************************************
00597 
00598 >   BOOL CSampleData::SetPrev(CSampleItem& Item)
00599 
00600     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00601     Created:    31/5/2000
00602     Inputs:     Item - the item to insert
00603     Outputs:    -
00604     Returns:    TRUE if successful, FALSE if we're already at the head of the array
00605     Purpose:    Decrements our internal index and then inserts Item into the array.
00606                 
00607     Notes:      
00608 ********************************************************************************************/
00609 
00610 BOOL CSampleData::SetPrev(CSampleItem& Item)
00611 {
00612     BOOL Retval = FALSE;
00613     if (m_pSampleData != NULL)
00614     {
00615         // we are not allowed to be setting data when the sample rate is not 1.0
00616         if (m_CollectionSampleRate < MIN_COLLECTION_SAMPLE_RATE || 
00617             m_CollectionSampleRate > MAX_COLLECTION_SAMPLE_RATE)
00618         {
00619             ERROR3("Attempting to set data when SampleRate != 1");
00620             return Retval;
00621         }
00622         if (DecrementInternalIndex(&m_CollectionInternalIndex))
00623         {
00624             if (m_CollectionInternalIndex != -1.0)
00625             {
00626                 (*m_pSampleData)[size_t(m_CollectionInternalIndex)] = Item;
00627                 Retval = TRUE;
00628             }
00629             else
00630                 ERROR3("Attempting to SetPrev over the start of the array in CSampleData::SetPrev");
00631         }
00632             ERROR3("Unable to decrement index in CSampleData::SetPrev");
00633     }   
00634     return Retval;
00635 }
00636 
00637 /********************************************************************************************
00638 
00639 >   BOOL CSampleData::RemoveAt(UINT32 Index)
00640 
00641     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00642     Created:    31/5/2000
00643     Inputs:     Index - the position to remove from
00644     Outputs:    -
00645     Returns:    TRUE, unless we go over the end of the array
00646     Purpose:    Removes item at Index
00647                 
00648     Notes:      
00649 ********************************************************************************************/
00650 
00651 BOOL CSampleData::RemoveAt(UINT32 Index)
00652 {
00653     BOOL Retval = FALSE;
00654     if (m_pSampleData != NULL)
00655     {
00656         // we are not allowed to be setting data when the sample rate is not 1.0
00657         if (m_CollectionSampleRate < MIN_COLLECTION_SAMPLE_RATE || 
00658             m_CollectionSampleRate > MAX_COLLECTION_SAMPLE_RATE)
00659         {
00660             ERROR3("Attempting to remove data when SampleRate != 1");
00661             return FALSE;
00662         }
00663         if (SetInternalRetrievalIndex(Index))
00664         {
00665             m_pSampleData->erase( m_pSampleData->begin() + size_t(m_RetrievalInternalIndex) );
00666             Retval = TRUE;
00667             m_NumItems--;
00668         }
00669         else
00670             ERROR3("Attempting to remove beyond the end of the array in CSampleData::RemoveAt");
00671     }
00672     return Retval;
00673 }
00674 
00675 
00676 
00677 
00678 /********************************************************************************************
00679 
00680 >   BOOL CSampleData::GetAt(UINT32 Index, CSampleItem* pItem)
00681 
00682     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00683     Created:    31/5/2000
00684     Inputs:     Index - the index to retrieve from
00685     Outputs:    pItem - the item at index
00686     Returns:    TRUE if successful, FALSE if Index is invalid or there is no array
00687     Purpose:    Retrieves the item at Index
00688                 
00689     Notes:      All the access functions set the m_ListPosition member variable which records
00690                 the last list positon accessed.  This means that you can the use GetNext or
00691                 GetPrev to retrieve subsequent elements, which is much quicker than using
00692                 GetAt all the time.
00693 ********************************************************************************************/
00694 
00695 BOOL CSampleData::GetAt(UINT32 Index, CSampleItem* pItem)
00696 {
00697     ERROR2IF(pItem == NULL, FALSE, "Item pointer is NULL in CSampleData::GetAt");
00698 
00699     if (m_pSampleData != NULL)
00700     {
00701         if (SetInternalRetrievalIndex(Index))
00702         {
00703             //TRACEUSER( "Diccon", _T("Get At: "));
00704             CSampleItem TheItem;
00705             if (GetItemAtInternalIndex(m_RetrievalInternalIndex, &TheItem))
00706                 *pItem = TheItem;
00707             return TRUE;
00708         }
00709         else
00710             ERROR3("Trying to access element over the end of the array in CSampleData::GetAt"); 
00711     }
00712     return FALSE;
00713 }
00714 
00715 BOOL CSampleData::GetAtPos(double Index, CSampleItem* pItem)
00716 {
00717     ERROR2IF(pItem == NULL, FALSE, "Item pointer is NULL in CSampleData::GetAt");
00718 
00719     if (m_pSampleData != NULL)
00720     {
00721         //if (SetInternalRetrievalIndex(Index))
00722         {
00723             //TRACEUSER( "Diccon", _T("Get At: "));
00724 
00725             UINT32 rounded = (UINT32) Index;
00726 
00727             CSampleItem TheItem;
00728             if (GetItemAtInternalIndex((double) rounded, &TheItem))
00729                 *pItem = TheItem;
00730             return TRUE;
00731         }
00732         //else
00733         //  ERROR3("Trying to access element over the end of the array in CSampleData::GetAt"); 
00734     }
00735     return FALSE;
00736 }
00737 
00738 
00739 
00740 
00741 /********************************************************************************************
00742 
00743 >   BOOL CSampleData::GetNext(CSampleItem* pItem)
00744 
00745     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00746     Created:    31/5/2000
00747     Inputs:     -
00748     Outputs:    pItem - the tail item
00749     Returns:    TRUE if successful, FALSE if we are at the end of the array or it doesn't exist
00750     Purpose:    Increments the internal index, then retrieves the item at that index
00751                 
00752     Notes:      It is recommended that you do a GetAt before you start doing GetNexts, otherwise
00753                 I won't vouch for the position of the value of the internal index
00754 ********************************************************************************************/
00755 
00756 BOOL CSampleData::GetNext(CSampleItem* pItem)
00757 {
00758     BOOL Retval = FALSE;
00759     if (m_pSampleData != NULL)
00760     {
00761         //TRACEUSER( "Diccon", _T("Get Next: "));
00762         if (IncrementInternalIndex(&m_RetrievalInternalIndex))
00763         {
00764             // BODGE ALERT! if the retrieval index is -1 then this indicates that we
00765             // have reached the end of the array! However I am letting it pass on, 
00766             // and have inserted more bodge code at GetItemAtInternalIndex to return
00767             // the last item.
00768             
00769         //  if (m_RetrievalInternalIndex == -1.0)
00770         //      ERROR3("Invalid index in CSampleData::GetNext");
00771 
00772             {
00773                 if (GetItemAtInternalIndex(m_RetrievalInternalIndex, pItem))
00774                     Retval = TRUE;
00775             }
00776         }
00777         else
00778             ERROR3("Unable to increment index in CSampleData::GetNext");
00779     }
00780 
00781     return Retval;      
00782 }
00783 
00784 /********************************************************************************************
00785 
00786 >   BOOL CSampleData::GetPrev(CSampleItem* pItem)
00787 
00788     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00789     Created:    31/5/2000
00790     Inputs:     -
00791     Outputs:    pItem - the previous item in the array
00792     Returns:    TRUE if successful, FALSE if we are at the start of the array or it doesn't exist
00793     Purpose:    Decrements our internal index and retrieves the item at that position
00794                 
00795     Notes:      Really only works if the internal index has been set by a previous function such
00796                 as GetAt, SetAt, etc.
00797 ********************************************************************************************/
00798 
00799 BOOL CSampleData::GetPrev(CSampleItem* pItem)
00800 {
00801     BOOL Retval = FALSE;
00802     if (m_pSampleData != NULL)
00803     {
00804         if (DecrementInternalIndex(&m_RetrievalInternalIndex))
00805         {
00806             if (m_RetrievalInternalIndex != -1.0)
00807             {
00808                 if (GetItemAtInternalIndex(m_RetrievalInternalIndex, pItem))
00809                     Retval = TRUE;
00810             }   
00811         }
00812         else
00813             ERROR3("Unable to decrement index in CSampleData::GetPrev");
00814     }
00815     return Retval;
00816 }
00817 
00818 /********************************************************************************************
00819 
00820 >   INT32 CSampleData::GetCount()
00821 
00822     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00823     Created:    31/5/2000
00824     Inputs:     -
00825     Outputs:    -
00826     Returns:    the number of items in the array, or -1 if the array does not exist
00827     Purpose:    To find the number of items in the array
00828                 
00829 ********************************************************************************************/
00830 
00831 INT32 CSampleData::GetCount()
00832 {
00833     if (m_pSampleData != NULL)
00834         return (INT32)m_pSampleData->size();
00835 
00836     return -1;
00837 }
00838 
00839 /********************************************************************************************
00840 
00841 >   INT32 CSampleData::FreeExtra()
00842 
00843     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00844     Created:    31/5/2000
00845     Inputs:     -
00846     Outputs:    -
00847     Returns:    -
00848     Purpose:    Asks the array to free any unused memory above its current upper bound.  Recommneded
00849                 that you call this if you do a big SetSize and don't use it all
00850                 
00851 ********************************************************************************************/
00852 
00853 void CSampleData::FreeExtra()
00854 {
00855     if (m_pSampleData != NULL)
00856         m_pSampleData->resize( (INT32)m_NumItems );
00857 }
00858 
00859 /********************************************************************************************
00860 
00861 >   BOOL CSampleData::InsertNewData(UINT32 Index, CSampleData* pData)
00862 
00863     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00864     Created:    31/5/2000
00865     Inputs:     Index - the index to insert at
00866                 pData - array of items to insert
00867     Outputs:    -
00868     Returns:    TRUE if successful
00869     Purpose:    To insert pData into our data array at Index.  This function does the shuffling
00870                 of existing array elements in order to insert the new data
00871                 
00872 ********************************************************************************************/
00873 
00874 BOOL CSampleData::InsertNewData(UINT32 Index, CSampleData* pData)
00875 {
00876     ERROR2IF(pData == NULL, FALSE, "Attempting to insert null array in CSampleData::InsertNewData");
00877     ERROR2IF(m_pSampleData == NULL, FALSE, "Member data array is NULL in CSampleData::InsertNewData");
00878 
00879     if (Index > m_pSampleData->size() - 1)
00880     {
00881         ERROR3("Attempting to insert beyond end of array in CSampleData::InsertNewData");
00882         return FALSE;
00883     }
00884 
00885     // find out how many elements we are inserting
00886     INT32 NumNewItems = (INT32)pData->GetNumItems();
00887     if (NumNewItems <= 0)
00888     {
00889         ERROR3("Attempting to insert zero or fewer elements in BOOL CSampleData::InsertNewData");
00890         return FALSE;
00891     }
00892 
00893     // Set our sample rates to 1.0 so that we don't skip any elements
00894     m_CollectionSampleRate = 1.0;
00895     m_RetrievalSampleRate  = 1.0;
00896     pData->SetRetrievalSampleRate(1.0);
00897     // work out how many elements we have to move
00898     size_t NumMoveItems = m_pSampleData->size() - 1 - Index;
00899 
00900         // this keeps track of where we're moving from
00901     UINT32 MoveIndex = (UINT32)m_pSampleData->size() - 1;
00902     m_NumItems = m_pSampleData->size() + NumNewItems;
00903     // extend our array so we have room for the new data
00904     m_pSampleData->resize((INT32)m_NumItems);
00905 
00906     // start at the tail and work down, shifting existing elements up to make room
00907     CSampleItem TheItem;
00908     BOOL KeepGoing = GetAt(MoveIndex, &TheItem);
00909 //  TRACEUSER( "Diccon", _T("SHIFTING %d ITEMS UP FROM %d TO %d\n"), NumMoveItems, MoveIndex-NumMoveItems, MoveIndex-NumMoveItems + NumNewItems);
00910     while (NumMoveItems && KeepGoing)
00911     {
00912         // copy the item to its place further up in the array
00913         (*m_pSampleData)[MoveIndex + NumNewItems] = TheItem;
00914         // get the next item
00915         KeepGoing = GetPrev(&TheItem);
00916         MoveIndex--;
00917         NumMoveItems--;
00918     }
00919 //  TRACEUSER( "Diccon", _T("FINISHED SHIFTING UP\n"));
00920     // now we can insert our new data at Index
00921 
00922     // get the first item and set it, so we can use GetNext for each array
00923     KeepGoing = pData->GetAt(0, &TheItem);
00924     if (KeepGoing)
00925         SetAt(Index, TheItem);
00926     UINT32 Counter = 0;
00927 //  TRACEUSER( "Diccon", _T("INSERTING NEW DATA\n"));
00928     while (NumNewItems && KeepGoing)
00929     {
00930         if (KeepGoing) KeepGoing = pData->GetNext(&TheItem);
00931         if (KeepGoing)  SetNext(TheItem);
00932         //TRACEUSER( "Diccon", _T("Inserting item %d\n"), TheItem.m_Pressure);
00933         NumNewItems--;
00934         Counter++;
00935     }
00936     
00937     //TRACEUSER( "Diccon", _T("Added %d items at index %d\n"), Counter, Index);
00938     // hopefully that should have done the trick!
00939 
00940     return TRUE;
00941 }
00942 
00943 /********************************************************************************************
00944 
00945 >   BOOL CSampleData::RemoveData(UINT32 StartIndex, UINT32 EndIndex, SampleArray* pArray)
00946 
00947     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
00948     Created:    31/5/2000
00949     Inputs:     StartIndex - the index to start removing from
00950                 EndIndex - the index to stop removing at
00951     Outputs:    pArray (optional) - an array to store the removed elements in
00952     Returns:    TRUE if successful
00953     Purpose:    To remove all the items between StartIndex and EndIndex, and optionally record
00954                 them in pArray
00955                 
00956 ********************************************************************************************/
00957 
00958 BOOL CSampleData::RemoveData(UINT32 StartIndex, UINT32 EndIndex, SampleArray* pArray)
00959 {
00960     // do some checks
00961     ERROR2IF(m_pSampleData == NULL, FALSE, "Attempting to remove from an array that doesn't exist in CSampleData::RemoveData");
00962     ERROR2IF(EndIndex <= StartIndex, FALSE, "Invalid indexes in CSampleData::RemoveData");
00963 
00964     UINT32 UpperBound = (UINT32)m_pSampleData->size() - 1;
00965     if (StartIndex > UpperBound || EndIndex > UpperBound)
00966     {
00967         ERROR3("Attempting to remove items beyond the bounds of the array in CSampleData::RemoveData");
00968         return FALSE;
00969     }
00970     // Set our samples rate to 1.0 so that we don't skip any elements
00971     m_CollectionSampleRate = 1.0;
00972     m_RetrievalSampleRate  = 1.0;
00973     
00974     // find out how many we're dealing with
00975     UINT32 NumRemoveItems = EndIndex - StartIndex;
00976     
00977 //  TRACEUSER( "Diccon", _T("COPYING ITEMS TO BE REMOVED\n"));
00978     // first copy the removed items to the new array (if relevant)
00979     if (pArray != NULL)
00980     {
00981         pArray->resize( NumRemoveItems );
00982         CSampleItem TheItem;
00983         for (UINT32 i = 0; i < NumRemoveItems; i++)
00984         {
00985             TheItem = (*m_pSampleData)[i + StartIndex];
00986             (*pArray)[i] = TheItem;
00987         //  TRACEUSER( "Diccon", _T("Removing data %d\n"), TheItem.m_Pressure);
00988         }
00989     }
00990     
00991     // now copy all elements beyond EndIndex back to StartIndex
00992     UINT32 NumMoveItems = UpperBound - EndIndex;
00993     UINT32 NumItemsMoved = 0;
00994     CSampleItem TheItem;
00995     // EndIndex +1 ??
00996 //  UINT32 Index = StartIndex;
00997 //  TRACEUSER( "Diccon", _T("SHIFTING ITEMS DOWN FROM %d TO %d\n"), EndIndex, Index);
00998 //  TRACEUSER( "Diccon", _T("Upper bound = %d\n"), UpperBound);
00999     BOOL ok = GetAt(EndIndex, &TheItem);
01000     INT32 RemoveCount = NumRemoveItems;
01001     while ((NumItemsMoved <= NumMoveItems) && ok)
01002     {
01003         (*m_pSampleData)[StartIndex++] = TheItem;
01004         ok = GetNext(&TheItem);
01005         NumItemsMoved++;
01006         if (RemoveCount > 0)
01007         {
01008             RemoveCount--;
01009             m_NumItems--; // decrement the number of items
01010         }
01011     }
01012     
01013 //  TRACEUSER( "Diccon", _T("Removed %d items\n"), EndIndex - Index);
01014 //  TRACEUSER( "Diccon", _T("Moved %d items from index %d to index %d\n"), NumItemsMoved, EndIndex, Index); 
01015     // shrink the array to the new size
01016     m_pSampleData->resize( m_NumItems );
01017 
01018     return TRUE;
01019 }
01020 
01021 
01022 /********************************************************************************************
01023 
01024 >   BOOL CSampleData::SetInternalCollectionIndex(UINT32 IndexRequested)
01025 
01026     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01027     Created:    31/5/2000
01028     Inputs:     IndexRequested - the requested index to set the array pointer to
01029     Outputs:    -
01030     Returns:    TRUE, unless index converts to an internal index that is out of bounds
01031     Purpose:    Sets our collection internal array index to the position corresponding to the 
01032                 requested index
01033                 
01034 ********************************************************************************************/
01035 
01036 BOOL CSampleData::SetInternalCollectionIndex(UINT32 Index)
01037 {
01038     ERROR2IF(m_pSampleData == NULL, FALSE, "Sample data is null in CSampleData::SetInternalIndex");
01039 
01040     BOOL Retval = FALSE;
01041 
01042     double TempIndex = m_CollectionSampleRate * Index;
01043     if (TempIndex <= (double)m_pSampleData->size() - 1 && TempIndex >= 0)
01044     {
01045         m_CollectionInternalIndex = TempIndex;
01046         Retval = TRUE;
01047     }
01048     else
01049         ERROR3("Attempting to set internal index beyond the end of the array in CSampleData::SetInternalIndex"); 
01050 
01051     return Retval;
01052 }
01053 
01054 
01055 /********************************************************************************************
01056 
01057 >   BOOL CSampleData::SetInternalRetrievalIndex(UINT32 IndexRequested)
01058 
01059     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01060     Created:    31/5/2000
01061     Inputs:     IndexRequested - the requested index to set the array pointer to
01062     Outputs:    -
01063     Returns:    TRUE, unless index converts to an internal index that is out of bounds
01064     Purpose:    Sets our Retrieval internal array index to the position corresponding to the 
01065                 requested index
01066                 
01067 ********************************************************************************************/
01068 
01069 BOOL CSampleData::SetInternalRetrievalIndex(UINT32 Index)
01070 {
01071     ERROR2IF(m_pSampleData == NULL, FALSE, "Sample data is null in CSampleData::SetInternalIndex");
01072 
01073     BOOL Retval = FALSE;
01074 
01075     double TempIndex = m_RetrievalSampleRate * Index;
01076     if (TempIndex <= (double)m_pSampleData->size() - 1)
01077     {
01078         m_RetrievalInternalIndex = TempIndex;
01079         Retval = TRUE;
01080     }
01081     else
01082         ERROR3("Attempting to set internal index beyond the end of the array in CSampleData::SetInternalIndex"); 
01083 
01084     return Retval;
01085 }
01086 
01087 
01088 /********************************************************************************************
01089 
01090 >   BOOL CSampleData::IncrementInternalIndex(double* pCurrentIndex)
01091     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01092     Created:    31/5/2000
01093     Inputs:     pCurrentIndex - the index to be incremented, this should really only be either
01094                 the collection index or the retrieval index
01095     Outputs:    -
01096     Returns:    TRUE, unless something goes wrong
01097     Purpose:    Increments our internal index counter, unless we have reached
01098                 the end of the array in which case we set the counter to -1
01099                 
01100 ********************************************************************************************/
01101 
01102 BOOL CSampleData::IncrementInternalIndex(double* pCurrentIndex)
01103 {
01104     // if we've already overrun then don't go any further
01105     if (*pCurrentIndex == -1)
01106         return TRUE;
01107 
01108     // not allowed to use indexes that aren't one of our members, also 
01109     // find out which sample rate to use here
01110     double SampleRate = 1.0;
01111     if (pCurrentIndex == &m_CollectionInternalIndex)
01112     {
01113         SampleRate = m_CollectionSampleRate;
01114     }
01115     else if (pCurrentIndex == &m_RetrievalInternalIndex)
01116     {
01117         SampleRate = m_RetrievalSampleRate;
01118     }
01119     else
01120     {
01121         ERROR3("Attempting to use non-member index in CSampleData::IncrementInternalIndex");
01122         return FALSE;
01123     }
01124 
01125     // we need to have valid sample data
01126     ERROR2IF(m_pSampleData == NULL, FALSE, "Sample data is null in CSampleData::IncrementInternalIndex");
01127 
01128     double TestIndex = *pCurrentIndex + SampleRate;
01129     //  TRACEUSER( "Diccon", _T("  Internal index = %f"), TestIndex);
01130     //  TRACEUSER( "Diccon", _T(", Upper bound = %f\n"), (double)(m_pSampleData->size() - 1));
01131     if (TestIndex <= (double)(m_pSampleData->size() - 1))
01132     {
01133         *pCurrentIndex += SampleRate;
01134     }
01135     else
01136     {
01137         
01138     //  TRACEUSER( "Diccon", _T("END OF ARRAY, Test index = %f, Num items = %d\n"), TestIndex, m_NumItems);
01139         *pCurrentIndex = -1;
01140         
01141     }
01142     
01143     
01144     return TRUE;
01145 }
01146 
01147 /********************************************************************************************
01148 
01149 >   BOOL CSampleData::DecrementInternalIndex(double* pCurrentIndex)
01150 
01151     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01152     Created:    31/5/2000
01153     Inputs:     pCurrentIndex - the index to be decremented, this should really only be either
01154                 the collection index or the retrieval index
01155     Outputs:    -
01156     Returns:    TRUE, unless something went wrong
01157     Purpose:    Decrements our internal array pointer and index counter, unless we have reached
01158                 the start of the array in which case we set it to -1.
01159 ********************************************************************************************/
01160 
01161 BOOL CSampleData::DecrementInternalIndex(double* pCurrentIndex)
01162 {
01163     // not allowed to use indexes that aren't one of our members, also 
01164     // find out which sample rate to use here
01165     double SampleRate = 1.0;
01166     if (pCurrentIndex == &m_CollectionInternalIndex)
01167     {
01168         SampleRate = m_CollectionSampleRate;
01169     }
01170     else if (pCurrentIndex == &m_RetrievalInternalIndex)
01171     {
01172         SampleRate = m_RetrievalSampleRate;
01173     }
01174     else
01175     {
01176         ERROR3("Attempting to use non-member index in CSampleData::DecrementInternalIndex");
01177         return FALSE;
01178     }
01179 
01180     // we need to have valid sample data
01181     ERROR2IF(m_pSampleData == NULL, FALSE, "Sample data is null in CSampleData::DecrementInternalIndex");
01182 
01183     double TestIndex = *pCurrentIndex - SampleRate;
01184     if (TestIndex > 0)
01185     {
01186         *pCurrentIndex -= SampleRate;
01187     }
01188     else
01189     {
01190         *pCurrentIndex = -1;
01191     }
01192     return TRUE;
01193 }
01194 
01195 
01196 /********************************************************************************************
01197 
01198 >   BOOL CSampleData::GetItemAtInternalIndex(double Index, CSampleItem* pItem)
01199 
01200     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01201     Created:    31/5/2000
01202     Inputs:     Index - the index to get the value from.  Note that this does not have to be
01203                 an integer, should really be the collection or retrieval index only
01204     Outputs:    pointer to item retrieved
01205     Returns:    TRUE if all went well, FALSE if we don't have an array or the index is invalid
01206     Purpose:    Retrieves the item in the array indicated by the current internal index.  Note
01207                 that it is possible that this index may not be an integer in which case this 
01208                 function will generate a new CSampleItem by interpolation
01209                 
01210 ********************************************************************************************/
01211 
01212 BOOL CSampleData::GetItemAtInternalIndex(double Index, CSampleItem* pItem)
01213 {
01214     // no reason why you shouldn't be using this function on values other than our member
01215     // indexes but that is not the intended purpose of this fn. hence the ERROR3
01216     //if (Index != m_CollectionInternalIndex && Index != m_RetrievalInternalIndex)
01217 //      ERROR3("Attempting to use non-member index in CSampleData::GetItemAtInternalIndex");
01218 
01219     ERROR2IF(m_pSampleData == NULL, FALSE, "Sample data is null in CSampleData::GetItemAtInternalIndex");
01220 
01221     BOOL Retval = FALSE;
01222     //TRACEUSER( "Diccon", _T("Retrieving item at %f\n"), Index);
01223 
01224     double UpperBound = (double)m_pSampleData->size() - 1;
01225     
01226     // If our index is -1 then we have run off the end of the array, so return the last item
01227     if (Index == -1)
01228         Index = UpperBound;
01229 
01230     if (Index <= UpperBound)
01231     {
01232         size_t LowIndex = (UINT32)Index;
01233         if (LowIndex > m_NumItems)
01234             //ERROR3("Attempting to access data that has not been collected in CSampleData::GetItemAtInternalIndex");
01235             LowIndex = m_NumItems; //bodge alert!
01236 
01237         UINT32 HighIndex = (UINT32)Index+1;
01238         if (HighIndex < m_NumItems)
01239         {
01240             double Proportion = Index - (double)LowIndex;
01241             CSampleItem LowItem = (*m_pSampleData)[LowIndex];
01242             CSampleItem HighItem = (*m_pSampleData)[HighIndex];
01243             CSampleItem NewItem = LowItem.InterpolateItems(HighItem, (1-Proportion));
01244             //TRACEUSER( "Diccon", _T("Lo = %d, Hi = %d, Prop  =%f, Pressure = %d\n"), LowIndex, HighIndex, Proportion, NewItem.m_Pressure);
01245             *pItem = NewItem;
01246         }
01247         else
01248             *pItem = (*m_pSampleData)[LowIndex];
01249         
01250         Retval = TRUE;
01251     }
01252     else
01253         ERROR3("Internal index is over the end of the array in CSampleData::GetItemAtInternalIndex");
01254     
01255     return Retval;
01256 }
01257 
01258 /*------------------------------------------------------------------------------------------
01259 -----------------------------------Other functions------------------------------------------
01260 -------------------------------------------------------------------------------------------*/
01261 
01262 /********************************************************************************************
01263 
01264 >   BOOL CSampleData::SetCollectionSampleRate(UINT32 Rate)
01265 
01266     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01267     Created:    31/5/2000
01268     Inputs:     Rate - the sample rate to use
01269     Outputs:    -
01270     Returns:    TRUE if Rate is within the set bounds
01271     Purpose:    Sets the sample rate to use for collecting data.  Note that for current purposes
01272                 this is only allowed to be 1.  So you probably won't be using this function 
01273                 very often.
01274 ********************************************************************************************/
01275 
01276 BOOL CSampleData::SetCollectionSampleRate(double Rate)
01277 {
01278     if (Rate < MIN_COLLECTION_SAMPLE_RATE || Rate > MAX_COLLECTION_SAMPLE_RATE)
01279     {
01280         ERROR3("Attempting to set invalid sample rate in CSampleData::SetCollectionSampleRate");
01281         return FALSE;
01282     }
01283 
01284     m_CollectionSampleRate = Rate;
01285 
01286     return TRUE;
01287 }
01288 
01289 /********************************************************************************************
01290 
01291 >   double CSampleData::GetCollectionSampleRate()
01292 
01293     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01294     Created:    31/5/2000
01295     Inputs:     -
01296     Outputs:    -
01297     Returns:    the current collection sample rate
01298     Purpose:    as above
01299                 
01300 ********************************************************************************************/
01301 
01302 double CSampleData::GetCollectionSampleRate()
01303 {
01304     return m_CollectionSampleRate;
01305 }
01306 
01307 /********************************************************************************************
01308 
01309 >   BOOL CSampleData::SetRetrievalSampleRate(UINT32 Rate)
01310 
01311     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01312     Created:    31/5/2000
01313     Inputs:     Rate - the sample rate to use
01314     Outputs:    -
01315     Returns:    TRUE if Rate is within the set bounds
01316     Purpose:    Sets the sample rate to use for retrieving data, 
01317 ********************************************************************************************/
01318 
01319 BOOL CSampleData::SetRetrievalSampleRate(double Rate)
01320 {
01321     // CGS:  because of the way that I now use this function, its NOT fair to do the following ....
01322     
01323     if (Rate < MIN_RETRIEVAL_SAMPLE_RATE || Rate > MAX_RETRIEVAL_SAMPLE_RATE)
01324     {
01325         TRACE( _T("Sample rate passed to CSampleData::SetRetrievalSampleRate was oustide of range!") );
01326         //ERROR3("Attempting to set invalid sample rate in CSampleData::SetRetrievalSampleRate");
01327         //return FALSE;
01328     }
01329 
01330     if (Rate < MIN_RETRIEVAL_SAMPLE_RATE) Rate = MIN_RETRIEVAL_SAMPLE_RATE;
01331     if (Rate > MAX_RETRIEVAL_SAMPLE_RATE) Rate = MAX_RETRIEVAL_SAMPLE_RATE;
01332 
01333     m_RetrievalSampleRate = Rate;
01334 
01335     return TRUE;
01336 }
01337 
01338 /********************************************************************************************
01339 
01340 >   double CSampleData::GetRetrievalSampleRate()
01341 
01342     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01343     Created:    31/5/2000
01344     Inputs:     -
01345     Outputs:    -
01346     Returns:    the current Retrieval sample rate
01347     Purpose:    as above
01348                 
01349 ********************************************************************************************/
01350 
01351 double CSampleData::GetRetrievalSampleRate()
01352 {
01353     return m_RetrievalSampleRate;
01354 }
01355 
01356 /********************************************************************************************
01357 
01358 >   void CSampleData::SetMaxPressure(UINT32 Max)
01359 
01360     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01361     Created:    31/5/2000
01362     Inputs:     Max - the maximum pressure value allowed by the current pressure device
01363     Outputs:    -
01364     Returns:    -
01365     Purpose:    To set our max pressure member.  Do this by querying the WinTab device BEFORE
01366                 you start collecting data.
01367                 
01368 ********************************************************************************************/
01369 
01370 void CSampleData::SetMaxPressure(UINT32 Max)
01371 {
01372     m_MaxPressure = Max;
01373     
01374     // +1 because values go from 0 -> MaxVal whereas we really want the number of values
01375     m_ScalePressure = (double)(MAXPRESSURE+1) / (Max+1); 
01376     
01377 }
01378 
01379 /********************************************************************************************
01380 
01381 >   UINT32 CSampleData::GetMaxPressure()
01382 
01383     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01384     Created:    31/5/2000
01385     Inputs:     -
01386     Outputs:    -
01387     Returns:    the maximum pressure value allowed by the device sending the pressure data
01388     Purpose:    as above
01389                 
01390 ********************************************************************************************/
01391 
01392 UINT32 CSampleData::GetMaxPressure()
01393 {
01394     return m_MaxPressure;
01395 }
01396 
01397 /********************************************************************************************
01398 
01399 >   void CSampleData::SetSampleArray(SampleArray* pArray)
01400 
01401     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01402     Created:    31/5/2000
01403     Inputs:     pArray - the array to set as a data member
01404     Outputs:    -
01405     Returns:    -
01406     Purpose:    sets the given array to use as our sample data
01407                 
01408 ********************************************************************************************/
01409 
01410 void CSampleData::SetSampleArray(SampleArray* pArray)
01411 {
01412     // if we've already got one then delete it
01413     if (m_pSampleData != NULL)
01414     {
01415         m_pSampleData->clear();
01416         delete m_pSampleData;
01417         m_pSampleData = NULL;
01418     }
01419     m_pSampleData = pArray;
01420 }
01421 
01422 /********************************************************************************************
01423 
01424 
01425 >   BOOL CSampleData::ReverseData()
01426 
01427     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01428     Created:    13/12/99
01429     Inputs:     -
01430     Returns:    TRUE if successful, FALSE if we didn't get the memory
01431     Purpose:    Reverses the items in the data array, or rather just copies them into a new one
01432 ********************************************************************************************/
01433 
01434 BOOL CSampleData::ReverseData()
01435 {
01436     if (m_pSampleData == NULL)
01437         return TRUE;  //EASY
01438 
01439     size_t ArraySize = m_NumItems;  
01440 
01441     if (ArraySize == 0)
01442         return TRUE;  // also easy
01443 
01444     // make a new array
01445     SampleArray* pNewArray = new SampleArray;
01446     if (pNewArray == NULL)
01447         return FALSE;
01448 
01449     pNewArray->resize( ArraySize );
01450 
01451     size_t UpperBound = ArraySize-1;
01452     CSampleItem TheItem;
01453 //  BOOL ok = TRUE;
01454     // take the item at the start of our member array and set it at the end of the new array
01455     for (UINT32 Counter = 0; Counter < (UINT32)ArraySize ; Counter++)
01456     {
01457         TheItem = (*m_pSampleData)[Counter];
01458         (*pNewArray)[UpperBound - Counter] = TheItem;
01459     }
01460     // swap the pointers
01461     SampleArray* pTemp = m_pSampleData;
01462     m_pSampleData = pNewArray;
01463     
01464     // clear out the original
01465     pTemp->clear();
01466     delete pTemp;
01467 
01468     return TRUE;
01469 }
01470 
01471 /********************************************************************************************
01472 
01473 
01474 >   void CSampleData::FinishSampling()
01475 
01476     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01477     Created:    13/12/99
01478     Inputs:     -
01479     Returns:    -
01480     Purpose:    Tells the object that sampling has finished.  As a security precaution we will 
01481                 add an extra 10 * m_RetrievalSampleRates worth of entries.
01482                 The real reason for this hack is that once the path is entered it is then smoothed,
01483                 which causes the path length to increase.  Since we never sampled over this increased
01484                 length we need to kind of pretend that we did.
01485 ********************************************************************************************/
01486 
01487 void CSampleData::FinishSampling()
01488 {
01489     if (m_pSampleData != NULL)
01490     {
01491         // find out how many items to insert
01492         UINT32 NumExtraItems = (UINT32)(m_RetrievalSampleRate * 10);
01493         
01494         // get the last item we inserted
01495         UINT32 InsertIndex = (UINT32)m_CollectionInternalIndex;
01496         CSampleItem TheItem = (*m_pSampleData)[InsertIndex];
01497         
01498         // make sure the array is big enough
01499         UINT32 CurrentSize = (INT32)m_pSampleData->size();
01500         if (CurrentSize < InsertIndex+NumExtraItems)
01501         {
01502             m_pSampleData->resize( CurrentSize + NumExtraItems );
01503         }
01504 
01505     
01506 
01507         for (UINT32 i = 1; i <= NumExtraItems; i++)
01508         {
01509             (*m_pSampleData)[InsertIndex + i] = TheItem;
01510             m_NumItems++;
01511         }
01512     }
01513 }
01514 /********************************************************************************************
01515 
01516 
01517 >   void CSampleData::SetNumItemsFromArraySize()
01518 
01519     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01520     Created:    13/12/99
01521     Inputs:     -
01522     Returns:    -
01523     Purpose:    Sets the num items member from the size of the array.  Note that you should
01524                 never really use this unless you are certain that a) your current m_NumItems
01525                 is incorrect and b)You are certain that your array contains nothing but valid
01526                 data.  
01527                 An example of when you should use this is if you decide to set the array from
01528                 out side, rather than collect it through sampling.  And you really shouldn't
01529                 be doing that either.
01530 ********************************************************************************************/
01531 
01532 void CSampleData::SetNumItemsFromArraySize()
01533 {
01534     if (m_pSampleData != NULL)
01535         m_NumItems = (UINT32)m_pSampleData->size();
01536     else
01537         m_NumItems = 0;
01538 }
01539 
01540 /********************************************************************************************
01541 
01542 
01543 >   BOOL CSampleData::ClipArray(UINT32 Size)
01544 
01545     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01546     Created:    13/12/99
01547     Inputs:     Size - the desired array size
01548     Returns:    TRUE unless Size is bigger than the array we have
01549     Purpose:    Clips the array to be the desired size, be careful with this as you will lose
01550                 all data beyond the Size'th index.
01551 ********************************************************************************************/
01552 
01553 BOOL CSampleData::ClipArray(size_t Size)
01554 {
01555     ERROR2IF(m_pSampleData == NULL, FALSE, "Sample data is NULL in CSampleData::ClipArray");
01556     ERROR2IF(Size > (UINT32)m_pSampleData->size(), FALSE, "Attempting to clip over the end of the array in CSampleData::ClipArray");
01557 
01558     m_pSampleData->resize( Size );
01559     if (m_NumItems > Size)
01560         m_NumItems = Size;
01561 
01562     return TRUE;
01563 }
01564 
01565 
01566 /********************************************************************************************
01567 
01568 >   BOOL CSampleData::ReSampleArray(SampleArray** ppArray, UINT32 NewNumItems)
01569 
01570     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01571     Created:    12/6/2000
01572     Inputs:     pArray      - the array to be resampled
01573                 NewNumItems - the number of items we want to end up with in the array
01574     Returns:    TRUE if successful, FALSE if something went wrong
01575     Purpose:    Resamples the data in the sample array so that we end up with NewNumItems in
01576                 the section required.  We will do this by selecting some resampling points in
01577                 the original array, maintain these points at the same proportional position 
01578                 and interpolate to get the new points.
01579     
01580      Notes:     Because, in reality most of our 'sampled' points are actually interpolated
01581                 from a smaller number of data points collected I feel that we don't actually
01582                 lose much accuracy if we just take one in every four points as a control point.
01583 
01584 ********************************************************************************************/
01585 
01586 BOOL CSampleData::ReSampleArray(SampleArray** ppArray, UINT32 NewNumItems)
01587 {
01588     SampleArray* pArray = *ppArray;
01589     // check our input conditions
01590     ERROR2IF(pArray == NULL, FALSE, "Sample array is NULL in CSampleData::ReSampleData");
01591 
01592     
01593     if (NewNumItems == 0)  // well this is easy
01594     {
01595         pArray->clear();
01596         return TRUE;
01597     }
01598     
01599     // allocate a new array to put the resampled data in
01600     SampleArray* pNewArray = new SampleArray;
01601     if (pNewArray == NULL)
01602         return FALSE;
01603     pNewArray->resize( NewNumItems );
01604 
01605     // how many items per control item
01606     UINT32 ItemsPerControl = 4;  // magic number alert!!
01607 
01608     // Insert the control points into the new array
01609     if (!InsertControlPoints(ItemsPerControl, pArray, pNewArray))
01610     {
01611         pNewArray->clear();
01612         delete pNewArray;
01613         return FALSE;
01614     }
01615 
01616     // proceed through the new array interpolating between the control points.
01617     // We will be able to tell the control points because their coordinates will be non-zero
01618 
01619     UINT32 ControlIndex1 = 0;  // first point is a control point
01620     UINT32 ControlIndex2 = 0;
01621     CSampleItem TheItem;
01622 
01623     UINT32 Index = 0;
01624 
01625     while (Index < NewNumItems)
01626     {
01627         TheItem = (*pNewArray)[Index];
01628         if (TheItem.m_Coord.x != 0 && TheItem.m_Coord.y != 0)  // got another control
01629         {
01630             ControlIndex2 = Index;
01631             if (Index != 0)
01632                 InterpolateItems(ControlIndex1, ControlIndex2, pNewArray);
01633             ControlIndex1 = ControlIndex2;  // current control becomes first control
01634         }
01635         Index++;
01636     }
01637     
01638     // now we have to destroy the original array and swap the pointers
01639     delete pArray;
01640     *ppArray = pNewArray;
01641 
01642     return TRUE;
01643 }
01644 
01645 
01646 /********************************************************************************************
01647 
01648 >   BOOL CSampleData::InsertControlPoints(UINT32 Frequency, SampleArray* pOriginal, 
01649                                         SampleArray* pNew)
01650 
01651     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01652     Created:    12/6/2000
01653     Inputs:     Frequency - the number of indexes per control point. i.e. 4 = a control point
01654                 every 4th index.
01655                 pOriginal - the original array
01656                 pNew      - the new array, this MUST be allocated AND sized
01657     Returns:    TRUE if successful, FALSE if something went wrong
01658     Purpose:    As part of the ReSampleArray process this function takes the case where we need
01659                 to increase the number of control points.  It therefore proceeds through the original
01660                 array copying control points over at the same proportional position as they were in 
01661                 the original array.  
01662     
01663 
01664 ********************************************************************************************/
01665 
01666 BOOL CSampleData::InsertControlPoints(UINT32 Frequency, SampleArray* pOriginal, SampleArray* pNew)
01667 {
01668     ERROR2IF(pOriginal == NULL, FALSE, "Original array is NULL in CSampleData::InsertControlPoints");
01669     ERROR2IF(pNew      == NULL, FALSE, "New array is NULL in CSampleData::InsertControlPoints");
01670 
01671     double NumOrigItems = (double)pOriginal->size();
01672     double NumNewItems  = (double)pNew->size();
01673 
01674     INT32    OrigIndex = 0;
01675     double dOrigIndex = 0;
01676     INT32 NewIndex  = 0;
01677 
01678     CSampleItem TheItem;
01679     double OrigProportion;
01680     while (OrigIndex < NumOrigItems)
01681     {
01682         TheItem = (*pOriginal)[OrigIndex];
01683         OrigProportion = dOrigIndex / NumOrigItems;
01684         NewIndex = (INT32)(OrigProportion * NumNewItems);
01685         if (NewIndex < NumNewItems)
01686             (*pNew)[NewIndex] = TheItem;
01687         else
01688             ERROR3("Attempting to set over the end of the new array in CSampleData::InsertControlPoints");
01689         OrigIndex += Frequency;
01690         dOrigIndex += Frequency;
01691     }
01692     return TRUE;
01693 }
01694 
01695 /********************************************************************************************
01696 
01697 >   BOOL CSampleData::GetArraySection(UINT32 StartIndex, UINT32 EndIndex, SampleArray* pSection)
01698 
01699     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01700     Created:    12/6/2000
01701     Inputs:     StartIndex - the internal index at which to start the resampling
01702                 EndIndex   - the internal index to finish the resampling
01703                 pSection   - a to an allocated sample array
01704     Outputs:    Allocatest the array and fills it with data from the section
01705     Returns:    TRUE if successful, FALSE if something went wrong
01706     Purpose:    To copy the data from the section specified into a new array that we will 
01707                 create.
01708 
01709     Errors:     if StartIndex or EndIndex are invalid, or if we don't have a sample array
01710     
01711 ********************************************************************************************/
01712 
01713 BOOL CSampleData::GetArraySection(UINT32 StartIndex, UINT32 EndIndex, SampleArray* pSection)
01714 {
01715     // check our input conditions
01716     ERROR2IF(pSection == NULL, FALSE, "Sample array is NULL in CSampleData::GetArraySection");
01717     if (EndIndex <= StartIndex || EndIndex > m_NumItems)
01718     {
01719         ERROR3("Invalid indexes in CSampleData::GetArraySection");
01720         return FALSE;
01721     }
01722     
01723     UINT32 NumItems = EndIndex - StartIndex;
01724     pSection->resize(NumItems);
01725 
01726     // we want to make sure we retrieve all the items
01727     m_RetrievalSampleRate = 1.0;
01728 
01729     // We have to do the first one manually, due to my rather clumsy implementation
01730     CSampleItem TheItem;
01731     BOOL ok = GetAt(StartIndex, &TheItem);
01732     if (ok) 
01733         (*pSection)[0] =  TheItem;
01734     else
01735         ERROR3("Failed to retrieve first item in CSampleData::GetArraySection");
01736     
01737     UINT32 Counter = 1;
01738     while (ok && (Counter < NumItems))
01739     {
01740         ok = GetNext(&TheItem);
01741         (*pSection)[Counter] = TheItem;
01742         Counter++;
01743     }
01744     
01745     // Did we copy the right number of items?
01746     if (Counter != NumItems)
01747     {
01748         ERROR3("Error copying data in CSampleData::GetArraySection");
01749         ok = FALSE;
01750     }
01751     else
01752         ok = TRUE;
01753     return ok;
01754 }
01755 
01756 
01757 /********************************************************************************************
01758 
01759 
01760 >   BOOL CSampleData::InterpolateItems(UINT32 StartIndex, UINT32 EndIndex, SampleArray* pArray)
01761 
01762     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01763     Created:    13/6/2000
01764     Inputs:     StartIndex, EndIndex - the indexes to interpolate between
01765                 pArray - the array to do the interpolatin' on
01766     Outputs:    the interpolated array
01767     Returns:    TRUE unless the indexes are wack
01768     Purpose:    Interpolates between the two indexes in the array, creating intermediate items
01769                 and inserting them
01770 
01771 ********************************************************************************************/
01772 
01773 BOOL CSampleData::InterpolateItems(UINT32 StartIndex, UINT32 EndIndex, SampleArray* pArray)
01774 {
01775     ERROR2IF(pArray == NULL, FALSE, "Sample array is NULL in CSampleData::InterpolateItems");
01776     size_t              MaxIndex = pArray->size() - 1;
01777 
01778     if (EndIndex <= StartIndex  || EndIndex > MaxIndex)
01779     {
01780         ERROR3("Invalid indexes in CSampleData::InterpolateItems");
01781         return FALSE;
01782     }
01783     // get the two items to interpolate between
01784     CSampleItem FirstItem = (*pArray)[StartIndex];
01785     CSampleItem LastItem  = (*pArray)[EndIndex];
01786 
01787     // get the proportional changes for each step
01788     UINT32 NumItems = EndIndex - StartIndex;
01789     double ItemProportion = 1 / (double)NumItems;
01790 
01791     MILLIPOINT XVal = (INT32)((double)(LastItem.m_Coord.x - FirstItem.m_Coord.x) * ItemProportion);
01792     MILLIPOINT YVal = (INT32)((double)(LastItem.m_Coord.y - FirstItem.m_Coord.y) * ItemProportion);
01793     INT32 PressVal  = (INT32) (((double)(LastItem.m_Pressure - FirstItem.m_Pressure) * ItemProportion));
01794 
01795     UINT32 Index = StartIndex + 1;
01796     CSampleItem NewItem = FirstItem;
01797     while (Index < EndIndex)
01798     {
01799         NewItem.m_Coord.x += XVal;
01800         NewItem.m_Coord.y += YVal;
01801         NewItem.m_Pressure += PressVal;
01802         (*pArray)[Index] = NewItem;
01803         Index++;
01804     }
01805     return TRUE;
01806 }
01807 
01808 /********************************************************************************************
01809 
01810 
01811 >   BOOL CSampleData::WriteNative(CXaraFileRecord* pRecord)
01812 
01813     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01814     Created:    13/12/99
01815     Inputs:     pRecord - the record to write to
01816     Returns:    TRUE if the Node has written out a record to the filter
01817     Purpose:    Writes out the data contained in this SampleData to a record
01818 
01819 ********************************************************************************************/
01820 
01821 BOOL CSampleData::WriteNative(CXaraFileRecord* pRecord)
01822 {
01823     ERROR2IF(pRecord == NULL, FALSE, "Record is NULL in CSampleData::WriteNative");
01824 
01825     BOOL ok = TRUE;
01826     ok = pRecord->WriteINT32((INT32)m_NumItems);
01827 
01828     if (m_pSampleData != NULL)
01829     {
01830         CSampleItem TheItem;
01831         
01832         SetRetrievalSampleRate(1.0); // as we want 
01833         BOOL KeepWriting  = GetAt(0, &TheItem);  // get the first itemto save out every item
01834         
01835 
01836         UINT32 Counter = 0;
01837         // note that GetNext returns FALSE it just means we've reached the end, not an error
01838         while (ok && Counter <= m_NumItems && KeepWriting)
01839         {
01840             if (ok) ok = TheItem.WriteNative(pRecord);
01841             KeepWriting = GetNext(&TheItem);
01842             Counter++;
01843         }
01844     }
01845     return ok;
01846 }
01847 
01848 /*-------------------------------------------------------------------------------------------
01849 ------------------------------CPressureSampler implementation-------------------------------------
01850 ---------------------------------------------------------------------------------------------
01851 */
01852 
01853 /********************************************************************************************
01854 
01855 >   CDistanceSampler::CDistanceSampler()
01856 
01857     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01858     Created:    31/5/2000
01859     Inputs:     -
01860     Outputs:    -
01861     Returns:    this object
01862     Purpose:    default constructor
01863                 
01864     Notes:      
01865 ********************************************************************************************/
01866 
01867 CDistanceSampler::CDistanceSampler()
01868 {
01869     m_SampleDistance = MIN_BRUSH_SPACING;
01870     m_DistanceSinceLastSample = -1;
01871     m_DistanceSoFar = 0;
01872     m_TotalDistance = 0;
01873     m_ItemsInserted = 0;
01874     m_DistanceSinceLastData = 0;
01875     m_ItemRemainder = 0.0;
01876 }
01877 
01878 /********************************************************************************************
01879 
01880 >   CDistanceSampler::~CDistanceSampler()
01881 
01882     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01883     Created:    31/5/2000
01884     Inputs:     -
01885     Outputs:    -
01886     Returns:    this object
01887     Purpose:    destructor
01888                 
01889     Notes:      
01890 ********************************************************************************************/
01891 
01892 CDistanceSampler::~CDistanceSampler()
01893 {
01894 
01895 }
01896 
01897 /********************************************************************************************
01898 
01899 >   BOOL CDistanceSampler::SetSampleDistance(MILLIPOINT Distance)
01900 
01901     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01902     Created:    31/5/2000
01903     Inputs:     Distance - the distance to sample at
01904     Outputs:    -
01905     Returns:    TRUE, unless Distance is out of bounds
01906     Purpose:    Sets the sample distance, I can't see why you would wish to sample at anything
01907                 other than MIN_BRUSH_SPACING, but each to their own
01908                 
01909     Notes:      
01910 ********************************************************************************************/
01911 
01912 BOOL CDistanceSampler::SetSampleDistance(MILLIPOINT Distance)
01913 {
01914     if (Distance < MIN_BRUSH_SPACING || Distance > MAX_BRUSH_SPACING)
01915     {
01916         ERROR3("Invalid distaance in CDistanceSampler::SetSampleDistance");
01917         return FALSE;
01918     }
01919     m_SampleDistance = Distance;
01920 
01921     return TRUE;
01922 }
01923 
01924 /********************************************************************************************
01925 
01926 >   BOOL CDistanceSampler::SetSampleDistance(MILLIPOINT Distance)
01927 
01928     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01929     Created:    31/5/2000
01930     Inputs:     -
01931     Outputs:    -
01932     Returns:    our sample distance
01933     Purpose:    access fn.
01934                 
01935     Notes:      
01936 ********************************************************************************************/
01937 
01938 MILLIPOINT CDistanceSampler::GetSampleDistance()
01939 {
01940     return m_SampleDistance;
01941 }
01942 
01943 /********************************************************************************************
01944 
01945 >   BOOL CDistanceSampler::CollectData(DocCoord Coord,  UINT32 Pressure)
01946 
01947     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
01948     Created:    31/5/2000
01949     Inputs:     Coord - the current coordinate
01950                 Pressure - the current pressure
01951     Outputs:    -
01952     Returns:    TRUE if successful, FALSE if something went wrong
01953     Purpose:    This function is in charge of doing the actual sampling of data
01954                 
01955     Notes:      
01956 ********************************************************************************************/
01957 
01958 BOOL CDistanceSampler::CollectData(DocCoord Coord, UINT32 Pressure)
01959 {
01960     // first up check that we have set the max pressure value
01961     ERROR2IF(m_MaxPressure == 0, FALSE, "You're supposed to set the Max Pressure value BEFORE you collect data");
01962     ERROR2IF(Pressure > m_MaxPressure, FALSE, "Pressure is greater than maximum value in CDistanceSampler::CollectData");
01963 
01964     BOOL ok = FALSE;
01965     // first up, if we are initialised to -1 then this is the first point, which we want
01966     if (m_DistanceSinceLastSample == -1)
01967     {
01968         if (m_ScalePressure != 1.0)
01969             Pressure = (UINT32)(m_ScalePressure * Pressure);
01970         CSampleItem TheItem(Coord, 0, Pressure);
01971         ok = SetAt(0, TheItem);
01972         m_DistanceSinceLastSample = 0;
01973 //      TRACEUSER( "Diccon", _T("Recording pressure %d at 0\n"), Pressure);
01974         m_LastItemStored = TheItem;
01975         m_LastItem = TheItem;
01976         m_LastCoord = Coord;
01977 
01978     }
01979     else
01980     {
01981         // find out how far we've gone
01982         MILLIPOINT Dist = (MILLIPOINT)Coord.Distance(m_LastItem.m_Coord);
01983         m_DistanceSinceLastData      = Dist;
01984         m_DistanceSinceLastSample   += Dist;
01985         m_TotalDistance             += Dist;
01986     //  TRACEUSER( "Diccon", _T("Received Pressure %d at Distance %d\n"), Pressure ,m_TotalDistance);
01987         // work out how many new items we need to make, and the proportional values to give to each
01988         double NumInsertItems = (double)m_DistanceSinceLastSample / (double)m_SampleDistance;
01989         if (NumInsertItems > 1)
01990         {
01991             if (m_ItemRemainder > 1) // if our remainder total adds up to >1 then add one more
01992             {
01993                 NumInsertItems++;
01994                 m_ItemRemainder--;
01995             }
01996             double ItemProportion = 1 / NumInsertItems;
01997         
01998             // work out the values that we need to add on for each step
01999             MILLIPOINT XVal = (INT32)((double)(Coord.x - m_LastItem.m_Coord.x) * ItemProportion);
02000             MILLIPOINT YVal = (INT32)((double)(Coord.y - m_LastItem.m_Coord.y) * ItemProportion);
02001             double dPressure = (double)Pressure * m_ScalePressure;
02002             INT32 PressVal  = (INT32)((dPressure - (double)m_LastItemStored.m_Pressure) * ItemProportion);
02003             m_ItemsInserted += (UINT32)NumInsertItems;
02004             //TRACEUSER( "Diccon", _T("INSERTED %d ITEMS\n"), m_ItemsInserted); 
02005             CSampleItem TheItem = m_LastItemStored;
02006             while (NumInsertItems > 1)
02007             {
02008                 m_DistanceSoFar += m_SampleDistance;
02009                 TheItem.m_Pressure += PressVal;
02010                 TheItem.m_Coord.x += XVal;
02011                 TheItem.m_Coord.y += YVal;
02012                 TheItem.m_Distance = m_DistanceSoFar;
02013                 ok = SetNext(TheItem, TRUE);
02014                 NumInsertItems--;
02015                 m_DistanceSinceLastSample -= m_SampleDistance;
02016                 //TRACEUSER( "Diccon", _T("Recording pressure %d at %d\n"), TheItem.m_Pressure, m_DistanceSoFar);
02017             }
02018             // add the remainder to our remainder counter
02019             m_ItemRemainder += NumInsertItems;
02020 
02021             m_LastItemStored = TheItem;
02022 
02023         }
02024         else
02025             ok = TRUE;
02026     }
02027     m_LastItem.m_Pressure = Pressure;
02028     m_LastItem.m_Coord    = Coord;
02029     return ok;
02030 }
02031 
02032 
02033 /********************************************************************************************
02034 
02035 >   BOOL CDistanceSampler::SetSampleRateFromSpacing(MILLIPOINT Spacing)
02036 
02037     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02038     Created:    31/5/2000
02039     Inputs:     Spacing - the spacing between brush objects
02040     Outputs:    -
02041     Returns:    TRUE so long as spacing is between bounds
02042     Purpose:    Given the spacing between objects this works out the sample rate at which
02043                 we want to retrieve objects
02044     Notes:      
02045 ********************************************************************************************/
02046 
02047 BOOL CDistanceSampler::SetSampleRateFromSpacing(MILLIPOINT Spacing)
02048 {
02049     if (/*Spacing < MIN_BRUSH_SPACING ||*/ Spacing > MAX_BRUSH_SPACING)
02050     {
02051         ERROR3("Attempting to set invalid spacing value");
02052         return FALSE;
02053     }
02054 
02055     /* recall that sample rate 1 : Spacing = MIN_BRUSH_SPACING
02056                    sample rate 2 : Spacing = 2 * MIN_BRUSH_SPACING
02057                    sample rate 3 : Spacing = 3 * .. etc. */
02058 
02059     m_RetrievalSampleRate = ((double)Spacing / (double)MIN_BRUSH_SPACING) ;
02060 
02061     return TRUE;
02062 }
02063 
02064 
02065 /********************************************************************************************
02066 
02067 >   UINT32 CDistanceSampler::GetInternalIndexFromDistance(MILLIPOINT Distance)
02068 
02069     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02070     Created:    31/5/2000
02071     Inputs:     Distance - the distance along the path
02072     Outputs:    -
02073     Returns:    the internal index into the distance array at that distance, or -1 if something goes wrong
02074     Purpose:    If you want to find out what index corresponds to Distance then call this,
02075                 actually all it does is divide by the minimum spacing. Note that it will always
02076                 round down.
02077     ERRORS:     Negative distance being passed in, Distance resulting in index which is off the
02078                 end of the array.
02079     Notes:      
02080 ********************************************************************************************/
02081 
02082 INT32 CDistanceSampler::GetInternalIndexFromDistance(MILLIPOINT Distance)
02083 {
02084     if (Distance < 0)
02085     {
02086         ERROR3("Negative distance in CDistanceSampler::GetInternalIndexFromDistance");
02087         return -1;
02088     }
02089 
02090     INT32 Index = Distance / MIN_BRUSH_SPACING;
02091 
02092     if (Index > (INT32)m_NumItems)
02093         Index = -1;
02094     return Index;
02095 }
02096 
02097 
02098 /********************************************************************************************
02099 
02100 >   CDistanceSampler* CDistanceSampler::MakeCopy()
02101 
02102     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02103     Created:    31/5/2000
02104     Inputs:     -
02105     Outputs:    -
02106     Returns:    a copy of this object, unless something goes wrong (i.e memory) in which case NULL
02107     Purpose:    Makes a copy of this sample data. Most of the work is done in the base class
02108                 but we need to also copy a few members over
02109                 
02110     Notes:      
02111 ********************************************************************************************/
02112 
02113 CDistanceSampler* CDistanceSampler::MakeCopy()
02114 {
02115     CDistanceSampler* pNewData = new CDistanceSampler;
02116 
02117     if (pNewData == NULL)
02118         return NULL;
02119 
02120     if (!pNewData->InitialiseData(m_NumItems))
02121     {
02122         delete pNewData;
02123         return NULL;
02124     }
02125 
02126     m_RetrievalSampleRate = 1; // make sure we get all the items
02127 
02128     CSampleItem TheItem;
02129 
02130     // unfortunately my implementation is a bit clumsy so we have to do the first item
02131     // by hand
02132     BOOL    Getok = GetAt(0, &TheItem);
02133     BOOL    Setok = pNewData->SetAt(0, TheItem);
02134     //TRACEUSER( "Diccon", _T("Copying pressure %d\n"), TheItem.m_Pressure);
02135     if (Getok == FALSE || Setok ==  FALSE)
02136         ERROR3("Failed to get or set first item in CSampleData::MakeCopy");
02137 
02138     UINT32 Counter = 1;
02139     // now we can loop through the rest
02140     while (Getok && Setok)
02141     {
02142         Getok = GetNext(&TheItem);
02143         Setok = pNewData->SetNext(TheItem);
02144         //TRACEUSER( "Diccon", _T("Copying pressure %d\n"), TheItem.m_Pressure);
02145         Counter++;
02146     }
02147 
02148     pNewData->m_DistanceSoFar = TheItem.m_Distance;
02149 
02150     if (Counter != m_NumItems)
02151         TRACEUSER( "Diccon", _T("CSampleData::MakeCopy - Num items copied = %d, Actual num items = %d\n"), Counter, m_NumItems);
02152 
02153 //  pNewData->SetSampleDistance(m_SampleDistance);
02154     return pNewData;
02155 }
02156 
02157 
02158 /********************************************************************************************
02159 
02160 >   BOOL CDistanceSampler::GetDataSection(MILLIPOINT Start, MILLIPOINT End, CDistanceSampler* pSection)
02161     
02162     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02163     Created:    12/6/2000
02164     Inputs:     Start, End - the distances between which we want to get the data from
02165                 pSection   - pointer to an allocated CDistanceSampler
02166     Outputs:    Initialises pSection with data between the two distances
02167     Returns:    TRUE if successful, FALSE if something went wrong
02168     Purpose:    Retrieves the data between Start and End and puts it into the sampler provided.
02169 
02170     Errors:     if Start or End are invalid, or if we don't have a sample array
02171     See Also:   CSampleData::GetArraySection
02172 
02173     Notes:      If this fn. goes wrong you are responsible for deleting the CDistanceSampler
02174 ********************************************************************************************/
02175 
02176 BOOL CDistanceSampler::GetDataSection(MILLIPOINT Start, MILLIPOINT End, CDistanceSampler* pSection)
02177 {   
02178     ERROR2IF(pSection == NULL, FALSE, "Sampler is NULL in CDistanceSampler::GetDataSection");
02179 
02180     if (Start < 0 || End < 0 || (End <= Start))
02181     {
02182         ERROR3("Invalid distances in CSampleData::ReSample");
02183         return FALSE;
02184     }
02185     // I guess if the caller hasn't allocated the sampler then we can do it, under duress..
02186     if (pSection == NULL)
02187     {
02188         ERROR3("You haven't initialised the distance sampler.  Well I suppose I can do it for you...");
02189         pSection = new CDistanceSampler;
02190         if (pSection == NULL)
02191         {
02192             ERROR3("Well actually I can't, sorry must bail");
02193             return FALSE;
02194         }
02195     }
02196     // get the indexes of the start and end points
02197     INT32 StartIndex = GetInternalIndexFromDistance(Start);
02198     INT32 EndIndex   = GetInternalIndexFromDistance(End);
02199 
02200     if (StartIndex == -1 || EndIndex == -1)
02201     {
02202         ERROR3("Error getting indexes in CDistanceSampler::ReSample");
02203         return FALSE;
02204     }
02205 
02206     // figure out how many items in the new length
02207     INT32 NewNumItems = (EndIndex - StartIndex) / MIN_BRUSH_SPACING;
02208 
02209     // initialise the data
02210     if (!pSection->InitialiseData(NewNumItems))
02211         return FALSE;
02212 
02213     // call the helper function to do the work
02214     BOOL ok = GetArraySection((UINT32)StartIndex, (UINT32)EndIndex, pSection->GetSampleArray());
02215     if (ok)
02216         pSection->SetNumItemsFromArraySize();
02217 
02218     return ok;
02219 }
02220 
02221 
02222 
02223 /********************************************************************************************
02224 
02225 >   BOOL CDistanceSampler::ReSample(MILLIPOINT NewLength)
02226 
02227     Author:     Diccon_Yamanaka (Xara Group Ltd) <camelotdev@xara.com>
02228     Created:    31/5/2000
02229     Inputs:     NewLength - the new length to sample over
02230     Outputs:    -
02231     Returns:    TRUE if all went well, FALSE if not
02232     Purpose:    If we want to change the distance that we sampled over then we must resample
02233                 the data to make it fit.  
02234                 
02235     Notes:      In truth most of the work is done in the base class. Here we simply calculate the
02236                 new number of items that we need and pass it along
02237 ********************************************************************************************/
02238 
02239 BOOL CDistanceSampler::ReSample(MILLIPOINT NewLength)
02240 {
02241     //checks
02242     if (NewLength <= 0 || m_pSampleData == NULL)
02243     {
02244         ERROR3("Invalid entry conditions in CDistanceSampler::ReSample");
02245         return FALSE;
02246     }
02247 
02248     // find out the new number of items
02249     INT32 NewNumItems = NewLength / MIN_BRUSH_SPACING;
02250 
02251     m_DistanceSoFar = NewLength;
02252 
02253     BOOL ok = ReSampleArray(&m_pSampleData, NewNumItems);
02254     if (ok)
02255         SetNumItemsFromArraySize();  // make sure our number of items is up to date
02256 
02257     return ok;
02258 
02259 }

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