valfunc.cpp

Go to the documentation of this file.
00001 // $Id: valfunc.cpp 1517 2006-07-24 21:05:42Z gavin $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 // Implementation of ValueFunction classes (used in stroke providing)
00099 
00100 #include "camtypes.h"
00101 
00102 #include <math.h>
00103 #include "valfunc.h"
00104 
00105 #include "cxftags.h"
00106 //#include "cxfrec.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "fixmem.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00108 //#include "list.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00109 
00110 
00111 CC_IMPLEMENT_DYNAMIC(ValueFunction,                     ListItem)
00112     CC_IMPLEMENT_DYNAMIC(ValueFunctionConstant,         ValueFunction)
00113     CC_IMPLEMENT_DYNAMIC(ValueFunctionRandom,           ValueFunction)
00114     CC_IMPLEMENT_DYNAMIC(ValueFunctionRamp,             ValueFunction)
00115         CC_IMPLEMENT_DYNAMIC(ValueFunctionRampLinear,   ValueFunctionRamp)
00116         CC_IMPLEMENT_DYNAMIC(ValueFunctionRampS,        ValueFunctionRamp)
00117         CC_IMPLEMENT_DYNAMIC(ValueFunctionRampS2,       ValueFunctionRamp)
00118         CC_IMPLEMENT_DYNAMIC(ValueFunctionRampL,        ValueFunctionRamp)
00119         CC_IMPLEMENT_DYNAMIC(ValueFunctionRampL2,       ValueFunctionRamp)
00120         CC_IMPLEMENT_DYNAMIC(ValueFunctionDoubleRampS,  ValueFunctionRamp)
00121         CC_IMPLEMENT_DYNAMIC(ValueFunctionSawTooth,     ValueFunctionRamp)
00122         CC_IMPLEMENT_DYNAMIC(ValueFunctionPropeller,    ValueFunctionRamp)
00123         CC_IMPLEMENT_DYNAMIC(ValueFunctionIntestine,    ValueFunctionRamp)
00124         CC_IMPLEMENT_DYNAMIC(ValueFunctionDecay,        ValueFunctionRamp)
00125         CC_IMPLEMENT_DYNAMIC(ValueFunctionBevelEnds,    ValueFunctionRamp)
00126     CC_IMPLEMENT_DYNAMIC(ValueFunctionBlip,             ValueFunction)
00127         CC_IMPLEMENT_DYNAMIC(ValueFunctionTeardrop,     ValueFunctionBlip)
00128         CC_IMPLEMENT_DYNAMIC(ValueFunctionTeardropCurvedEnd, ValueFunctionBlip)
00129         CC_IMPLEMENT_DYNAMIC(ValueFunctionEllipse,      ValueFunctionBlip)
00130         CC_IMPLEMENT_DYNAMIC(ValueFunctionThumbtack,    ValueFunctionBlip)
00131     CC_IMPLEMENT_DYNAMIC(ValueFunctionPressure,         ValueFunction)
00132         CC_IMPLEMENT_DYNAMIC(ValueFunctionPressureS,    ValueFunctionPressure)
00133     CC_IMPLEMENT_DYNAMIC(ValueFunctionSmoothStroke,     ValueFunction)
00134         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Yacht,     ValueFunctionSmoothStroke)
00135         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Iron,      ValueFunctionSmoothStroke)
00136         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Reed,      ValueFunctionSmoothStroke)
00137         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Meteor,    ValueFunctionSmoothStroke)
00138         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Petal,     ValueFunctionSmoothStroke)
00139         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Comet,     ValueFunctionSmoothStroke)
00140         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Fallout,   ValueFunctionSmoothStroke)
00141         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Torpedo,   ValueFunctionSmoothStroke)
00142         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Missile,   ValueFunctionSmoothStroke)
00143         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Convex,    ValueFunctionSmoothStroke)
00144         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Concave,   ValueFunctionSmoothStroke)
00145         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_SlimBlip,  ValueFunctionSmoothStroke)
00146         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Cigar,     ValueFunctionSmoothStroke)
00147         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Cigar2,    ValueFunctionSmoothStroke)
00148         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Cigar3,    ValueFunctionSmoothStroke)
00149         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_OceanLiner,ValueFunctionSmoothStroke)
00150         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Goldfish,  ValueFunctionSmoothStroke)
00151         CC_IMPLEMENT_DYNAMIC(ValueFunctionSS_Barb,      ValueFunctionSmoothStroke)
00152 
00153 
00154 // Declare smart memory handling in Debug builds
00155 #define new CAM_DEBUG_NEW
00156 
00157 
00158 const double Pi = 3.141592654;
00159 
00160 bool ValueFunctionSS_Yacht::bMadeTable      = false;
00161 bool ValueFunctionSS_Iron::bMadeTable       = false;
00162 bool ValueFunctionSS_Reed::bMadeTable       = false;
00163 bool ValueFunctionSS_Meteor::bMadeTable     = false;
00164 bool ValueFunctionSS_Petal::bMadeTable      = false;
00165 bool ValueFunctionSS_Comet::bMadeTable      = false;
00166 bool ValueFunctionSS_Fallout::bMadeTable    = false;
00167 bool ValueFunctionSS_Torpedo::bMadeTable    = false;
00168 bool ValueFunctionSS_Missile::bMadeTable    = false;
00169 bool ValueFunctionSS_Convex::bMadeTable     = false;
00170 bool ValueFunctionSS_Concave::bMadeTable    = false;
00171 bool ValueFunctionSS_SlimBlip::bMadeTable   = false;
00172 bool ValueFunctionSS_Cigar::bMadeTable      = false;
00173 bool ValueFunctionSS_Cigar2::bMadeTable     = false;
00174 bool ValueFunctionSS_Cigar3::bMadeTable     = false;
00175 bool ValueFunctionSS_OceanLiner::bMadeTable = false;
00176 bool ValueFunctionSS_Goldfish::bMadeTable   = false;
00177 bool ValueFunctionSS_Barb::bMadeTable       = false;
00178 
00179 //Used by the Smooth-Stroke Functions to retain bezier data...
00180 double ValueFunctionSmoothStroke::xvalue[18][256];
00181 double ValueFunctionSmoothStroke::yvalue[18][256];
00182 
00183 
00184 
00186 // ValueFunction base class
00188 
00189 
00190 List ValueFunction::RegisteredFunctions;
00191 
00192 
00193 /******************************************************************************************
00194 
00195 >   static BOOL ValueFunction::Init(void)
00196 
00197     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00198     Created:    27/1/97
00199 
00200     Returns:    TRUE if it initialises successfully
00201 
00202     Purpose:    Initialises all valueFunction classes defined in valfunc.cpp
00203 
00204                 Adds an instance of each ValueFunction to a dynamic list, which is
00205                 used to create new ValueFunctions as they are loaded from files.
00206                 Any dynamically added ValueFunction-derived class should add an
00207                 instance to the RegistreredFunctions list in order to properly
00208                 handle being re-loaded.
00209 
00210 ******************************************************************************************/
00211 
00212 BOOL ValueFunction::Init(void)
00213 {
00214 #define VFINIT(TYPE)                                \
00215     {                                               \
00216         TYPE *pFunc = new TYPE;                     \
00217         if (!pFunc)                                 \
00218             return(FALSE);                          \
00219         RegisteredFunctions.AddTail(pFunc);         \
00220     }
00221 
00222     VFINIT(ValueFunctionConstant);
00223     VFINIT(ValueFunctionRandom);
00224     VFINIT(ValueFunctionRampLinear);
00225     VFINIT(ValueFunctionRampS);
00226     VFINIT(ValueFunctionPressure);
00227     VFINIT(ValueFunctionPressureS);
00228     VFINIT(ValueFunctionBlip);
00229     VFINIT(ValueFunctionTeardrop);
00230     VFINIT(ValueFunctionEllipse);
00231     VFINIT(ValueFunctionThumbtack);
00232     VFINIT(ValueFunctionRampL);
00233     VFINIT(ValueFunctionRampS2);
00234     VFINIT(ValueFunctionRampL2);
00235     VFINIT(ValueFunctionTeardropCurvedEnd);
00236     VFINIT(ValueFunctionSawTooth);
00237     VFINIT(ValueFunctionPropeller);
00238     VFINIT(ValueFunctionDoubleRampS);
00239     VFINIT(ValueFunctionIntestine);
00240     VFINIT(ValueFunctionDecay);
00241     VFINIT(ValueFunctionBevelEnds);
00242     VFINIT(ValueFunctionSS_Reed);
00243     VFINIT(ValueFunctionSS_Meteor);
00244     VFINIT(ValueFunctionSS_Petal);
00245     VFINIT(ValueFunctionSS_Comet);
00246     VFINIT(ValueFunctionSS_Barb);
00247     VFINIT(ValueFunctionSS_Concave);
00248     VFINIT(ValueFunctionSS_Convex);
00249     VFINIT(ValueFunctionSS_Iron);
00250     VFINIT(ValueFunctionSS_Torpedo);
00251     VFINIT(ValueFunctionSS_Missile);
00252     VFINIT(ValueFunctionSS_Goldfish);
00253     VFINIT(ValueFunctionSS_OceanLiner);
00254     VFINIT(ValueFunctionSS_Yacht);
00255     VFINIT(ValueFunctionSS_SlimBlip);
00256     VFINIT(ValueFunctionSS_Cigar);
00257     VFINIT(ValueFunctionSS_Cigar2);
00258     VFINIT(ValueFunctionSS_Cigar3);
00259     VFINIT(ValueFunctionSS_Fallout);
00260 
00261 #undef VFINIT
00262 
00263     return(TRUE);
00264 }
00265 
00266 
00267 
00268 /******************************************************************************************
00269 
00270 >   static void ValueFunction::DeInit(void)
00271 
00272     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00273     Created:    27/1/97
00274 
00275     Returns:    TRUE if it initialises successfully
00276 
00277     Purpose:    Initialises all valueFunction classes defined in valfunc.cpp
00278 
00279 ******************************************************************************************/
00280 
00281 void ValueFunction::DeInit(void)
00282 {
00283     RegisteredFunctions.DeleteAll();
00284 }
00285 
00286 
00287 
00288 /******************************************************************************************
00289 
00290 >   virtual BOOL ValueFunction::IsDifferent(ValueFunction *Other)
00291 
00292     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00293     Created:    8/1/97
00294 
00295     Inputs:     pOther - Another ValueFunction object to compare this one to
00296 
00297     Returns:    TRUE if the objects are considered different,
00298                 FALSE if they are considered identical
00299 
00300     Purpose:    Comparator.
00301                 Determines if 2 different ValueFunction objects are considered
00302                 different.
00303 
00304     Notes:      The base class simply checks if they are of the same runtime class
00305                 and returns TRUE if they are not. Derived classes which can differ
00306                 in content between instances must override this method.
00307 
00308 ******************************************************************************************/
00309 
00310 BOOL ValueFunction::IsDifferent(ValueFunction *pOther)
00311 {
00312     ERROR3IF(pOther == NULL, "Illegal NULL param");
00313     return(GetRuntimeClass() != pOther->GetRuntimeClass());
00314 }
00315 
00316 
00317 
00318 /******************************************************************************************
00319 
00320 >   static ValueFunction *ValueFunction::ReadFileRecord(CXaraFileRecord *pInputRecord)
00321 
00322     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00323     Created:    27/1/97
00324 
00325     Inputs:     pInputRecord - The file record to read from
00326 
00327     Returns:    NULL if it fails, else a pointer to a new object initialised from
00328                 the given file record.
00329 
00330     Purpose:    Main entry point for loading ValueFunctions from files. The caller
00331                 record handler passes the record in to this static function, and
00332                 the saved VF is re-constituted from the saved information. On return
00333                 the caller can read any extra values that they saved in the record.
00334 
00335     Notes:      This scans the member RegisteredFunction list to see if it can find
00336                 a ValueFunction of the appropriate type, and asks it to create a new
00337                 ValueFunction to be initialised from the given record (by calling
00338                 the virtual CreateAndReadFileRecord())
00339 
00340 ******************************************************************************************/
00341 
00342 ValueFunction *ValueFunction::ReadFileRecord(CXaraFileRecord *pInputRecord)
00343 {
00344     ERROR3IF(pInputRecord == NULL, "Illegal NULL params");
00345 
00346     INT32 ID;
00347     pInputRecord->ReadINT32(&ID);
00348 
00349     ValueFunction *pFunc = (ValueFunction *) RegisteredFunctions.GetHead();
00350     while (pFunc != NULL)
00351     {
00352         if (pFunc->GetUniqueID() == ID)
00353             return(pFunc->CreateAndReadFileRecord(pInputRecord));
00354 
00355         pFunc = (ValueFunction *) RegisteredFunctions.GetNext(pFunc);
00356     }
00357 
00358     return(NULL);
00359 }
00360 
00361 
00362 
00363 /******************************************************************************************
00364 
00365 >   virtual CamelotFileRecord *ValueFunction::CreateAndWriteFileRecord(INT32 RecordTag,
00366                                                         INT32 DerivedBytes, INT32 ExtraBytes,
00367                                                         BaseCamelotFilter *pFilter)
00368 
00369     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00370     Created:    27/1/97
00371 
00372     Inputs:     RecordTag   - the tag to write this record under
00373 
00374                 DerivedBytes- The number of bytes of information the derived VF
00375                               class wishes to write to save its state. Space
00376                               for this infomation will be reserved in the new record
00377 
00378                 ExtraBytes  - The number of extra bytes of information the caller
00379                               will write into the record after caling this function
00380                               (Space for this many extra bytes will be reserved by
00381                               this function when it creates the new file record)
00382                               This may be 0 or more bytes.
00383 
00384                 pFilter     - The filter to write to
00385 
00386     Returns:    NULL if it failed, else a pointer to a record which saves the state
00387                 of this valueFunction object. Once the caller has written the record,
00388                 they MUST DELETE it.
00389 
00390                 This base-class function only writes the ValueFunction header for
00391                 the record data. The caller must append its own state information
00392                 to this header - see the record description below.
00393 
00394     Purpose:    Creates an output record containing an embedded ValueFunction description.
00395     
00396                 The record will be (4 + DerivedBytes + ExtraBytes) bytes in length, and
00397                 on return from this function, the first 4 bytes (only) will have been
00398                 written. The caller(s) must fill in the remainder.
00399 
00400                 All ValueFunction record data has 3 sections, whiich are recorded as follows:
00401                 1. ValueFunction header, identifying which type of VF is being saved.
00402                    This is written by the base class CreateAndWriteFileRecord
00403                         INT32 ValueFunctionUniqueID     (4 bytes)
00404 
00405                 2. Derived-class-data (0 or more bytes). This is written by the derived
00406                    class WriteFileRecord function, into the record returned from here.
00407                    This data must be DerivedBytes (0 or more) bytes in length.
00408 
00409                 3. Caller data. This is written by the caller of the derived function.
00410                    This data must be ExtraBytes (0 or more) bytes in length.
00411 
00412     SeeAlso:    ValueFunctionConstant::CreateAndReadFileRecord
00413 
00414 ******************************************************************************************/
00415 
00416 CamelotFileRecord *ValueFunction::CreateAndWriteFileRecord(INT32 RecordTag, 
00417                                                             INT32 DerivedBytes, INT32 ExtraBytes,
00418                                                             BaseCamelotFilter *pFilter)
00419 {
00420     ERROR3IF(pFilter == NULL, "Illegal NULL param");
00421     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::CreateAndWriteFileRecord");
00422 
00423     // Calculate how many bytes of information this VF will write.
00424     // We write a 4-byte "header", followed by the derived class data and the caller data
00425     const INT32 RecordSize = 4 + DerivedBytes + ExtraBytes;
00426 
00427     // Create an appropriate record, and write the header info to it
00428     CamelotFileRecord *pRec = new CamelotFileRecord(pFilter, RecordTag, RecordSize);
00429 
00430     // If that worked, then we now init & add our own data to the record
00431     if (pRec != NULL)
00432     {
00433         BOOL ok    = pRec->Init();
00434         if (ok) ok = pRec->WriteUINT32(GetUniqueID());
00435 
00436         if (!ok)        // If we failed, then clean up & return NULL
00437         {
00438             delete pRec;
00439             pRec = NULL;
00440         }
00441     }
00442 
00443     return(pRec);
00444 }
00445 
00446 
00447 
00448 
00449 
00451 // ValueFunctionConstant class
00453 
00454 /******************************************************************************************
00455 
00456 >   ValueFunctionConstant::ValueFunctionConstant(double Value)
00457 
00458     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00459     Created:    30/12/96
00460 
00461     Inputs:     Value   - The value to be used at all positions
00462 
00463     Purpose:    Constructor
00464                 The Constant ValueFunction always returns the same value!
00465 
00466 ******************************************************************************************/
00467 
00468 ValueFunctionConstant::ValueFunctionConstant(double Value)
00469 {
00470     Value1 = Value;
00471 }
00472 
00473 
00474 
00475 /******************************************************************************************
00476 
00477 >   virtual double ValueFunctionConstant::GetValue(double Position)
00478 
00479     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00480     Created:    30/12/96
00481 
00482     Inputs:     Position - A value between 0.0 and 1.0
00483     Returns:    A constant value (Value, as given in the constructor) representing
00484                 the value of the function at the given Position.
00485 
00486     Purpose:    To read the value of this function at a given position
00487 
00488     Notes:      Constant is a bit simple - it always returns the same value
00489 
00490 ******************************************************************************************/
00491 
00492 double ValueFunctionConstant::GetValue(double Position)
00493 {
00494     return(Value1);
00495 }
00496 
00497 
00498 
00499 /******************************************************************************************
00500 
00501 >   virtual ValueFunction *ValueFunctionConstant::Clone(void)
00502 
00503     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00504     Created:    8/1/97
00505 
00506     Returns:    NULL if it failed, else an exact copy of this object
00507 
00508     Purpose:    Clone operator. Creates an exact copy of this object
00509 
00510 ******************************************************************************************/
00511 
00512 ValueFunction *ValueFunctionConstant::Clone(void)
00513 {
00514     ValueFunction *pClone = new ValueFunctionConstant(Value1);
00515     return(pClone);
00516 }
00517 
00518 
00519 
00520 /******************************************************************************************
00521 
00522 >   virtual BOOL ValueFunctionConstant::IsDifferent(ValueFunction *Other)
00523 
00524     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00525     Created:    8/1/97
00526 
00527     Inputs:     pOther - Another ValueFunction object to compare this one to
00528 
00529     Returns:    TRUE if the objects are considered different,
00530                 FALSE if they are considered identical
00531 
00532     Purpose:    Comparator.
00533                 Determines if 2 different ValueFunction objects are considered
00534                 different.
00535 
00536     Notes:      Calls the base class to see if they are different classes,
00537                 and then compares identical classes by checking member vars
00538 
00539 ******************************************************************************************/
00540 
00541 BOOL ValueFunctionConstant::IsDifferent(ValueFunction *pOther)
00542 {
00543     if (ValueFunction::IsDifferent(pOther))
00544         return(TRUE);
00545     
00546     // Both objects are instances of this class, so compare them more carefully
00547     return(Value1 != ((ValueFunctionConstant *)pOther)->Value1);
00548 }
00549 
00550 
00551 
00552 /******************************************************************************************
00553 
00554 >   virtual CamelotFileRecord *ValueFunctionConstant::WriteFileRecord(INT32 RecordTag,
00555                                             INT32 ExtraBytes, BaseCamelotFilter *pFilter)
00556 
00557     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00558     Created:    27/1/97
00559 
00560     Inputs:     RecordTag   - the tag to write this record under
00561                 ExtraBytes  - The number of extra bytes of information the caller
00562                               will write into the record after caling this function
00563                               (Space for this many extra bytes will be reserved by
00564                               this function when it creates the new file record)
00565                               This may be 0 or more bytes.
00566                 pFilter     - The filter to write to
00567 
00568     Returns:    NULL if it failed, else a pointer to a record which saves the state
00569                 of this valueFunction object. Once the caller has written the record,
00570                 they MUST DELETE it.
00571 
00572     Purpose:    Saves a ValueFunction object to a Xara file.
00573                 This function will create a new variable-sized record with the given
00574                 record tag, and will write out whatever data is needed to save this
00575                 ValueFunction's state to the file.
00576                 
00577                 "ExtraBytes" bytes will be added to the record size to reserve space
00578                 at the end of the record for the caller to add their own data. This
00579                 is to allow ValueFunctions to be saved embedded in other object's
00580                 record structures (e.g. inside different types of attributes).
00581 
00582                 All ValueFunction record data has 3 sections, whiich are recorded as follows:
00583                 1. ValueFunction header, identifying which type of VF is being saved
00584                         INT32 ValueFunctionUniqueID     (4 bytes)
00585                 2. Derived-class-data (0 or more bytes). This particular class adds:
00586                         float ConstantValue             (4 bytes)
00587                 3. Caller data. This is written by the caller to the returned record
00588                    object. This data must be ExtraBytes (0 or more) bytes in length.
00589 
00590     SeeAlso:    ValueFunctionConstant::CreateAndReadFileRecord
00591 
00592 ******************************************************************************************/
00593 
00594 CamelotFileRecord *ValueFunctionConstant::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes,
00595                                                             BaseCamelotFilter *pFilter)
00596 {
00597     ERROR3IF(pFilter == NULL, "Illegal NULL param");
00598     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord");
00599 
00600     // Calculate how many bytes of information this VF will write. We do not include
00601     // the header info written by the base class or the ExtraInfo desired by the caller -
00602     // the base class adds all that in for us.
00603     const INT32 MyRecordSize = 4;
00604 
00605     // Create an appropriate record, and write our data to it
00606     CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter);
00607 
00608     if (pRec != NULL)
00609     {
00610         // Write out our ValueFunction's specific data. If it fails, then we'll return NULL
00611         if (!pRec->WriteFLOAT((float)Value1))
00612         {
00613             delete pRec;
00614             pRec = NULL;
00615         }
00616     }
00617 
00618     return(pRec);
00619 }
00620 
00621 
00622 
00623 /******************************************************************************************
00624 
00625 >   virtual ValueFunction *ValueFunctionConstant::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
00626 
00627     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00628     Created:    27/1/97
00629 
00630     Inputs:     pInputRecord - The file record to read
00631 
00632     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
00633                 whatever was saved in that record.
00634 
00635     Purpose:    Loads a ValueFunction object from a record which was saved into a file
00636                 using the WriteFileRecord call. This is called by the base class
00637                 loader routine ReadFileRecord, which finds an appropriate instance
00638                 of a derived class to call to load the data in question.
00639 
00640                 This method creates a new instance of this particular ValueFunction class
00641                 and then loads whatever information is necessary from the file to 
00642                 initialise itself properly. The record read-pointer is left pointing
00643                 at the end of the ValueFunction-saved data so that the caller can continue
00644                 reading their extra bytes of data after loading the ValueFunction.
00645 
00646     SeeAlso:    ValueFunctionConstant::WriteFileRecord;
00647                 ValueFunctionConstant::ReadFileRecord
00648 
00649 ******************************************************************************************/
00650 
00651 ValueFunction *ValueFunctionConstant::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
00652 {
00653     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
00654 
00655     float ConstValue = (float)1.0;
00656     pInputRecord->ReadFLOAT(&ConstValue);
00657 
00658     return(new ValueFunctionConstant((double) ConstValue));
00659 }
00660 
00661 
00662 
00663 
00664 
00665 
00666 
00667 
00668 
00670 // ValueFunctionRandom class
00672 
00673 /******************************************************************************************
00674 
00675 >   ValueFunctionRandom::ValueFunctionRandom(UINT32 Seed, double Min, double Max)
00676 
00677     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00678     Created:    30/12/96
00679 
00680     Inputs:     Seed    - The base random-number seed. This is combined with the
00681                           position value to generate a "random" number that will
00682                           not change for any given position/seed combination.
00683 
00684                 Min     - The minimum value you want returned
00685                 Max     - The maximum value you want returned
00686 
00687     Purpose:    Constructor
00688                 The Random ValueFunction returns a pseudo-random value between Min & Max
00689 
00690 ******************************************************************************************/
00691 
00692 ValueFunctionRandom::ValueFunctionRandom(UINT32 Seed, double Min, double Max)
00693 {
00694     ERROR3IF(Min > Max, "ValueFunctionRandom: Min should be smaller than Max");
00695 
00696     MinValue = Min;
00697     MaxValue = Max;
00698     SeedValue = Seed;
00699 
00700     // Fill in the array with random values
00701     srand(SeedValue);
00702     for (INT32 i = 0; i < NumRandomValues; i++)
00703         Array[i] = rand() & 0xffff;
00704 }
00705 
00706 
00707 
00708 /******************************************************************************************
00709 
00710 >   virtual double ValueFunctionRandom::GetValue(double Position)
00711 
00712     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00713     Created:    30/12/96
00714 
00715     Inputs:     Position - A value between 0.0 and 1.0
00716     Returns:    A "Random" value (based on the Seed, Min, and Max values given to the
00717                 constructor) representing the value of the function at the given Position.
00718 
00719     Purpose:    To read the value of this function at a given position
00720 
00721     Notes:      Random returns a pseudo-random value based on the position and the
00722                 Seed value, and clamped within the range given to the constructor.
00723                 If the Seed/Min/Max values are unchanged, the same position will
00724                 always return the same value.
00725 
00726 ******************************************************************************************/
00727 
00728 double ValueFunctionRandom::GetValue(double Position)
00729 {
00730     // Determine which array entry to use, and how much to linearly interpolate
00731     // between it and the next value
00732     INT32 Index = (INT32) floor(Position * (double)(0x400 * (NumRandomValues - 2)));
00733     double MixFraction = (double)(Index & 0x3ff) / (double)0x3ff;
00734 
00735     // Scale the Index value down into the proper range now, and make sure it's safe
00736     Index /= 0x400;
00737     if (Index < 0)
00738         Index = 0;
00739     if (Index > NumRandomValues - 2)
00740         Index = NumRandomValues - 2;
00741 
00742     // Get a random number between 0.0 and 1.0
00743     double Value = ((double)Array[Index] * (1.0 - MixFraction)) + ((double)Array[Index+1] * MixFraction);
00744     Value /= (double) 0xffff;
00745 
00746     // And scale the result into the range specified by the caller
00747     return( MinValue + (Value * (MaxValue - MinValue)) );
00748 }
00749 
00750 
00751 
00752 /******************************************************************************************
00753 
00754 >   virtual ValueFunction *ValueFunctionRandom::Clone(void)
00755 
00756     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00757     Created:    8/1/97
00758 
00759     Returns:    NULL if it failed, else an exact copy of this object
00760 
00761     Purpose:    Clone operator. Creates an exact copy of this object
00762 
00763 ******************************************************************************************/
00764 
00765 ValueFunction *ValueFunctionRandom::Clone(void)
00766 {
00767     ValueFunction *pClone = new ValueFunctionRandom(SeedValue, MinValue, MaxValue);
00768     return(pClone);
00769 }
00770 
00771 
00772 
00773 /******************************************************************************************
00774 
00775 >   virtual BOOL ValueFunctionRandom::IsDifferent(ValueFunction *Other)
00776 
00777     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00778     Created:    8/1/97
00779 
00780     Inputs:     pOther - Another ValueFunction object to compare this one to
00781 
00782     Returns:    TRUE, always
00783 
00784     Purpose:    Comparator.
00785                 Determines if 2 different ValueFunction objects are considered
00786                 different.
00787 
00788 ******************************************************************************************/
00789 
00790 BOOL ValueFunctionRandom::IsDifferent(ValueFunction *pOther)
00791 {
00792     return(TRUE);       // Random value functions always consider themselves different
00793 }
00794 
00795 
00796 
00797 /******************************************************************************************
00798 
00799 >   virtual CamelotFileRecord *ValueFunctionRandom::WriteFileRecord(INT32 RecordTag,
00800                                             INT32 ExtraBytes, BaseCamelotFilter *pFilter)
00801 
00802     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00803     Created:    27/1/97
00804 
00805     Inputs:     RecordTag   - the tag to write this record under
00806                 ExtraBytes  - The number of extra bytes of information the caller
00807                               will write into the record after caling this function
00808                               (Space for this many extra bytes will be reserved by
00809                               this function when it creates the new file record)
00810                               This may be 0 or more bytes.
00811                 pFilter     - The filter to write to
00812 
00813     Returns:    NULL if it failed, else a pointer to a record which saves the state
00814                 of this valueFunction object. Once the caller has written the record,
00815                 they MUST DELETE it.
00816 
00817     Purpose:    Saves a ValueFunction object to a Xara file.
00818                 This function will create a new variable-sized record with the given
00819                 record tag, and will write out whatever data is needed to save this
00820                 ValueFunction's state to the file.
00821                 
00822                 "ExtraBytes" bytes will be added to the record size to reserve space
00823                 at the end of the record for the caller to add their own data. This
00824                 is to allow ValueFunctions to be saved embedded in other object's
00825                 record structures (e.g. inside different types of attributes).
00826 
00827                 All ValueFunction record data has 3 sections, whiich are recorded as follows:
00828                 1. ValueFunction header, identifying which type of VF is being saved
00829                         INT32 ValueFunctionUniqueID     (4 bytes)
00830                 2. Derived-class-data (0 or more bytes). This particular class adds:
00831                         UINT32 SeedValue
00832                         float MinValue
00833                         float MaxValue                  (12 bytes)
00834                 3. Caller data. This is written by the caller to the returned record
00835                    object. This data must be ExtraBytes (0 or more) bytes in length.
00836 
00837     SeeAlso:    ValueFunctionRandom::CreateAndReadFileRecord
00838 
00839 ******************************************************************************************/
00840 
00841 CamelotFileRecord *ValueFunctionRandom::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes,
00842                                                             BaseCamelotFilter *pFilter)
00843 {
00844     ERROR3IF(pFilter == NULL, "Illegal NULL param");
00845     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord");
00846 
00847     // Calculate how many bytes of information this VF will write. We do not include
00848     // the header info written by the base class or the ExtraInfo desired by the caller -
00849     // the base class adds all that in for us.
00850     const INT32 MyRecordSize = 12;
00851 
00852     // Create an appropriate record, and write our data to it
00853     CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter);
00854 
00855     if (pRec != NULL)
00856     {
00857         // Write out our ValueFunction's specific data. If it fails, then we'll return NULL
00858         BOOL ok = TRUE;
00859         if (ok)     ok = pRec->WriteUINT32((UINT32)SeedValue);
00860         if (ok)     ok = pRec->WriteFLOAT((float)MinValue);
00861         if (ok)     ok = pRec->WriteFLOAT((float)MaxValue);
00862 
00863         if (!ok)
00864         {
00865             delete pRec;
00866             pRec = NULL;
00867         }
00868     }
00869 
00870     return(pRec);
00871 }
00872 
00873 
00874 
00875 /******************************************************************************************
00876 
00877 >   virtual ValueFunction *ValueFunctionRandom::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
00878 
00879     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00880     Created:    27/1/97
00881 
00882     Inputs:     pInputRecord - The file record to read
00883 
00884     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
00885                 whatever was saved in that record.
00886 
00887     Purpose:    Loads a ValueFunction object from a record which was saved into a file
00888                 using the WriteFileRecord call. This is called by the base class
00889                 loader routine ReadFileRecord, which finds an appropriate instance
00890                 of a derived class to call to load the data in question.
00891 
00892                 This method creates a new instance of this particular ValueFunction class
00893                 and then loads whatever information is necessary from the file to 
00894                 initialise itself properly. The record read-pointer is left pointing
00895                 at the end of the ValueFunction-saved data so that the caller can continue
00896                 reading their extra bytes of data after loading the ValueFunction.
00897 
00898     SeeAlso:    ValueFunctionRandom::WriteFileRecord;
00899                 ValueFunctionRandom::ReadFileRecord
00900 
00901 ******************************************************************************************/
00902 
00903 ValueFunction *ValueFunctionRandom::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
00904 {
00905     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
00906 
00907     UINT32 SeedValue = 1;
00908     float MinValue = (float) 0.0;
00909     float MaxValue = (float) 0.0;
00910 
00911     pInputRecord->ReadUINT32(&SeedValue);
00912     pInputRecord->ReadFLOAT(&MinValue);
00913     pInputRecord->ReadFLOAT(&MaxValue);
00914 
00915     return(new ValueFunctionRandom((UINT32) SeedValue, (double) MinValue, (double) MinValue));
00916 }
00917 
00918 
00919 
00920 
00921 
00922 
00923 
00925 // ValueFunctionRamp classes
00927 
00928 
00929 /******************************************************************************************
00930 
00931 >   ValueFunctionRamp::ValueFunctionRamp(double StartValue, double EndValue)
00932 
00933     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00934     Created:    30/12/96
00935 
00936     Inputs:     StartValue  - The value to be used at the 0.0 position
00937                 EndValue    - The value to be used at the 1.0 position
00938 
00939     Purpose:    Constructor
00940                 Ramp functions interpolate between two values in some fashion
00941                 Derived classes provide such things as linear and sine-wave interpolations
00942 
00943 ******************************************************************************************/
00944 
00945 ValueFunctionRamp::ValueFunctionRamp(double StartValue, double EndValue)
00946 {
00947     Value1 = StartValue;
00948     Value2 = EndValue;
00949 }
00950 
00951 
00952 
00953 /******************************************************************************************
00954 
00955 >   virtual BOOL ValueFunctionRamp::IsDifferent(ValueFunction *Other)
00956 
00957     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00958     Created:    8/1/97
00959 
00960     Inputs:     pOther - Another ValueFunction object to compare this one to
00961 
00962     Returns:    TRUE if the objects are considered different,
00963                 FALSE if they are considered identical
00964 
00965     Purpose:    Comparator.
00966                 Determines if 2 different ValueFunction objects are considered
00967                 different.
00968 
00969     Notes:      Calls the base class to see if they are different classes,
00970                 and then compares identical classes by checking member vars
00971 
00972 ******************************************************************************************/
00973 
00974 BOOL ValueFunctionRamp::IsDifferent(ValueFunction *pOther)
00975 {
00976     if (ValueFunction::IsDifferent(pOther))
00977         return(TRUE);
00978     
00979     // Both objects are instances of this class, so compare them more carefully
00980     return( (Value1 != ((ValueFunctionRamp *)pOther)->Value1) ||
00981             (Value2 != ((ValueFunctionRamp *)pOther)->Value2) );
00982 }
00983 
00984 
00985 
00986 /******************************************************************************************
00987 
00988 >   virtual CamelotFileRecord *ValueFunctionRamp::WriteFileRecord(INT32 RecordTag,
00989                                             INT32 ExtraBytes, BaseCamelotFilter *pFilter)
00990 
00991     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
00992     Created:    27/1/97
00993 
00994     Inputs:     RecordTag   - the tag to write this record under
00995                 ExtraBytes  - The number of extra bytes of information the caller
00996                               will write into the record after caling this function
00997                               (Space for this many extra bytes will be reserved by
00998                               this function when it creates the new file record)
00999                               This may be 0 or more bytes.
01000                 pFilter     - The filter to write to
01001 
01002     Returns:    NULL if it failed, else a pointer to a record which saves the state
01003                 of this valueFunction object. Once the caller has written the record,
01004                 they MUST DELETE it.
01005 
01006     Purpose:    Saves a ValueFunction object to a Xara file.
01007                 This function will create a new variable-sized record with the given
01008                 record tag, and will write out whatever data is needed to save this
01009                 ValueFunction's state to the file.
01010                 
01011                 "ExtraBytes" bytes will be added to the record size to reserve space
01012                 at the end of the record for the caller to add their own data. This
01013                 is to allow ValueFunctions to be saved embedded in other object's
01014                 record structures (e.g. inside different types of attributes).
01015 
01016                 All ValueFunction record data has 3 sections, whiich are recorded as follows:
01017                 1. ValueFunction header, identifying which type of VF is being saved
01018                         INT32 ValueFunctionUniqueID     (4 bytes)
01019                 2. Derived-class-data (0 or more bytes). This particular class adds:
01020                         float Value1
01021                         float Value2                    (8 bytes)
01022                 3. Caller data. This is written by the caller to the returned record
01023                    object. This data must be ExtraBytes (0 or more) bytes in length.
01024 
01025 ******************************************************************************************/
01026 
01027 CamelotFileRecord *ValueFunctionRamp::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes,
01028                                                             BaseCamelotFilter *pFilter)
01029 {
01030     ERROR3IF(pFilter == NULL, "Illegal NULL param");
01031     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord");
01032 
01033     // Calculate how many bytes of information this VF will write. We do not include
01034     // the header info written by the base class or the ExtraInfo desired by the caller -
01035     // the base class adds all that in for us.
01036     const INT32 MyRecordSize = 8;
01037 
01038     // Create an appropriate record, and write our data to it
01039     CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter);
01040 
01041     if (pRec != NULL)
01042     {
01043         BOOL ok = TRUE;
01044         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value1);
01045         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value2);
01046 
01047         if (!ok)            // If we failed, clean up & return NULL
01048         {
01049             delete pRec;
01050             pRec = NULL;
01051         }
01052     }
01053 
01054     return(pRec);
01055 }
01056 
01057 
01058 
01059 
01060 
01061 
01062 /******************************************************************************************
01063 
01064 >   virtual double ValueFunctionRampLinear::GetValue(double Position)
01065 
01066     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01067     Created:    30/12/96
01068 
01069     Inputs:     Position - A value between 0.0 and 1.0
01070     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01071                 the value of the function at the given Position.
01072 
01073     Purpose:    To read the value of this function at a given position
01074 
01075     Notes:      RampLinear is a linear interpolation between the start & end values
01076 
01077 ******************************************************************************************/
01078 
01079 double ValueFunctionRampLinear::GetValue(double Position)
01080 {
01081     return(((1.0 - Position) * Value1) + (Position * Value2));
01082 }
01083 
01084 
01085 
01086 /******************************************************************************************
01087 
01088 >   virtual ValueFunction *ValueFunctionRampLinear::Clone(void)
01089 
01090     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01091     Created:    8/1/97
01092 
01093     Returns:    NULL if it failed, else an exact copy of this object
01094 
01095     Purpose:    Clone operator. Creates an exact copy of this object
01096 
01097 ******************************************************************************************/
01098 
01099 ValueFunction *ValueFunctionRampLinear::Clone(void)
01100 {
01101     ValueFunction *pClone = new ValueFunctionRampLinear(Value1, Value2);
01102     return(pClone);
01103 }
01104 
01105 
01106 
01107 /******************************************************************************************
01108 
01109 >   virtual ValueFunction *ValueFunctionRampLinear::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01110 
01111     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01112     Created:    27/1/97
01113 
01114     Inputs:     pInputRecord - The file record to read
01115 
01116     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01117                 whatever was saved in that record.
01118 
01119     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01120                 using the WriteFileRecord call. This is called by the base class
01121                 loader routine ReadFileRecord, which finds an appropriate instance
01122                 of a derived class to call to load the data in question.
01123 
01124                 This method creates a new instance of this particular ValueFunction class
01125                 and then loads whatever information is necessary from the file to 
01126                 initialise itself properly. The record read-pointer is left pointing
01127                 at the end of the ValueFunction-saved data so that the caller can continue
01128                 reading their extra bytes of data after loading the ValueFunction.
01129 
01130     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01131 
01132 ******************************************************************************************/
01133 
01134 ValueFunction *ValueFunctionRampLinear::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01135 {
01136     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01137 
01138     float Value1 = (float) 1.0;
01139     float Value2 = (float) 0.0;
01140 
01141     pInputRecord->ReadFLOAT(&Value1);
01142     pInputRecord->ReadFLOAT(&Value2);
01143 
01144     return(new ValueFunctionRampLinear((double) Value1, (double) Value2));
01145 }
01146 
01147 
01148 
01149 
01150 
01151 /******************************************************************************************
01152 
01153 >   virtual double ValueFunctionRampS::GetValue(double Position)
01154 
01155     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01156     Created:    30/12/96
01157 
01158     Inputs:     Position - A value between 0.0 and 1.0
01159     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01160                 the value of the function at the given Position.
01161 
01162     Purpose:    To read the value of this function at a given position
01163 
01164     Notes:      RampS is a half sine-wave "S" shaped function
01165 
01166 ******************************************************************************************/
01167 
01168 double ValueFunctionRampS::GetValue(double Position)
01169 {
01170     const double MixValue   = (cos(Position * Pi) + 1.0) / 2.0;
01171 
01172     return((MixValue * Value1) + ((1.0 - MixValue) * Value2));
01173 }
01174 
01175 
01176 /******************************************************************************************
01177 
01178 >   virtual INT32 ValueFunctionRampS::GetMinimumRecursionDepth(void)
01179 
01180     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01181     Created:    9/10/2000
01182 
01183     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01184                 perform at minimum before declaring a line segment 'flat' enough
01185 
01186 ******************************************************************************************/
01187 
01188 INT32 ValueFunctionRampS::GetMinimumRecursionDepth()
01189 {
01190     return 2;
01191 }
01192 
01193 
01194 /******************************************************************************************
01195 
01196 >   virtual ValueFunction *ValueFunctionRampS::Clone(void)
01197 
01198     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01199     Created:    8/1/97
01200 
01201     Returns:    NULL if it failed, else an exact copy of this object
01202 
01203     Purpose:    Clone operator. Creates an exact copy of this object
01204 
01205 ******************************************************************************************/
01206 
01207 ValueFunction *ValueFunctionRampS::Clone(void)
01208 {
01209     ValueFunction *pClone = new ValueFunctionRampS(Value1, Value2);
01210     return(pClone);
01211 }
01212 
01213 
01214 
01215 /******************************************************************************************
01216 
01217 >   virtual ValueFunction *ValueFunctionRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01218 
01219     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01220     Created:    27/1/97
01221 
01222     Inputs:     pInputRecord - The file record to read
01223 
01224     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01225                 whatever was saved in that record.
01226 
01227     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01228                 using the WriteFileRecord call. This is called by the base class
01229                 loader routine ReadFileRecord, which finds an appropriate instance
01230                 of a derived class to call to load the data in question.
01231 
01232                 This method creates a new instance of this particular ValueFunction class
01233                 and then loads whatever information is necessary from the file to 
01234                 initialise itself properly. The record read-pointer is left pointing
01235                 at the end of the ValueFunction-saved data so that the caller can continue
01236                 reading their extra bytes of data after loading the ValueFunction.
01237 
01238     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01239 
01240 ******************************************************************************************/
01241 
01242 ValueFunction *ValueFunctionRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01243 {
01244     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01245 
01246     float Value1 = (float) 1.0;
01247     float Value2 = (float) 0.0;
01248 
01249     pInputRecord->ReadFLOAT(&Value1);
01250     pInputRecord->ReadFLOAT(&Value2);
01251 
01252     return(new ValueFunctionRampS((double) Value1, (double) Value2));
01253 }
01254 
01255 
01256 
01257 /******************************************************************************************
01258 
01259 >   virtual double ValueFunctionRampS2::GetValue(double Position)
01260 
01261     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01262     Created:    9/10/2000
01263 
01264     Inputs:     Position - A value between 0.0 and 1.0
01265     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01266                 the value of the function at the given Position.
01267 
01268     Purpose:    To read the value of this function at a given position
01269 
01270     Notes:      RampS2 is a half sine-wave "S" shaped function - Value2 set to none-zero
01271 
01272 ******************************************************************************************/
01273 
01274 double ValueFunctionRampS2::GetValue(double Position)
01275 {
01276     const double MixValue   = (cos(Position * Pi) + 1.0) / 2.0;
01277 
01278     return((MixValue * Value1) + ((1.0 - MixValue) * Value2));
01279 }
01280 
01281 
01282 
01283 /******************************************************************************************
01284 
01285 >   virtual ValueFunction *ValueFunctionRampS2::Clone(void)
01286 
01287     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01288     Created:    9/10/2000
01289 
01290     Returns:    NULL if it failed, else an exact copy of this object
01291 
01292     Purpose:    Clone operator. Creates an exact copy of this object
01293 
01294 ******************************************************************************************/
01295 
01296 ValueFunction *ValueFunctionRampS2::Clone(void)
01297 {
01298     ValueFunction *pClone = new ValueFunctionRampS2(Value1, Value2);
01299     return(pClone);
01300 }
01301 
01302 
01303 
01304 /******************************************************************************************
01305 
01306 >   virtual ValueFunction *ValueFunctionRampS2::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01307 
01308     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01309     Created:    9/10/2000
01310 
01311     Inputs:     pInputRecord - The file record to read
01312 
01313     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01314                 whatever was saved in that record.
01315 
01316     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01317                 using the WriteFileRecord call. This is called by the base class
01318                 loader routine ReadFileRecord, which finds an appropriate instance
01319                 of a derived class to call to load the data in question.
01320 
01321                 This method creates a new instance of this particular ValueFunction class
01322                 and then loads whatever information is necessary from the file to 
01323                 initialise itself properly. The record read-pointer is left pointing
01324                 at the end of the ValueFunction-saved data so that the caller can continue
01325                 reading their extra bytes of data after loading the ValueFunction.
01326 
01327     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01328 
01329 ******************************************************************************************/
01330 
01331 ValueFunction *ValueFunctionRampS2::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01332 {
01333     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01334 
01335     float Value1 = (float) 1.0;
01336     float Value2 = (float) 0.2;
01337 
01338     pInputRecord->ReadFLOAT(&Value1);
01339     pInputRecord->ReadFLOAT(&Value2);
01340 
01341     return(new ValueFunctionRampS2((double) Value1, (double) Value2));
01342 }
01343 
01344 /******************************************************************************************
01345 
01346 >   virtual INT32 ValueFunctionRampS2::GetMinimumRecursionDepth(void)
01347 
01348     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01349     Created:    9/10/2000
01350 
01351     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01352                 perform at minimum before declaring a line segment 'flat' enough
01353 
01354 ******************************************************************************************/
01355 
01356 INT32 ValueFunctionRampS2::GetMinimumRecursionDepth()
01357 {
01358     return 2;
01359 }
01360 
01361 
01362 
01363 
01364 
01365 /******************************************************************************************
01366 
01367 >   virtual double ValueFunctionRampL::GetValue(double Position)
01368 
01369     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01370     Created:    28/2/97
01371 
01372     Inputs:     Position - A value between 0.0 and 1.0
01373     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01374                 the value of the function at the given Position.
01375 
01376     Purpose:    To read the value of this function at a given position
01377 
01378     Notes:      RampL is a half sine-wave "S" shaped function
01379 
01380 ******************************************************************************************/
01381 
01382 double ValueFunctionRampL::GetValue(double Position)
01383 {
01384     const double MixValue   = cos((Pi/2.0) + (Position * Pi/2.0)) + 1.0;
01385 
01386     return((MixValue * Value1) + ((1.0 - MixValue) * Value2));
01387 }
01388 
01389 
01390 /******************************************************************************************
01391 
01392 >   virtual INT32 ValueFunctionRampL::GetMinimumRecursionDepth(void)
01393 
01394     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01395     Created:    9/10/2000
01396 
01397     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01398                 perform at minimum before declaring a line segment 'flat' enough
01399 
01400 ******************************************************************************************/
01401 
01402 INT32 ValueFunctionRampL::GetMinimumRecursionDepth()
01403 {
01404     return 2;
01405 }
01406 
01407 
01408 /******************************************************************************************
01409 
01410 >   virtual ValueFunction *ValueFunctionRampL::Clone(void)
01411 
01412     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01413     Created:    28/2/97
01414 
01415     Returns:    NULL if it failed, else an exact copy of this object
01416 
01417     Purpose:    Clone operator. Creates an exact copy of this object
01418 
01419 ******************************************************************************************/
01420 
01421 ValueFunction *ValueFunctionRampL::Clone(void)
01422 {
01423     ValueFunction *pClone = new ValueFunctionRampL(Value1, Value2);
01424     return(pClone);
01425 }
01426 
01427 
01428 
01429 /******************************************************************************************
01430 
01431 >   virtual ValueFunction *ValueFunctionRampL::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01432 
01433     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
01434     Created:    28/2/97
01435 
01436     Inputs:     pInputRecord - The file record to read
01437 
01438     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01439                 whatever was saved in that record.
01440 
01441     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01442                 using the WriteFileRecord call. This is called by the base class
01443                 loader routine ReadFileRecord, which finds an appropriate instance
01444                 of a derived class to call to load the data in question.
01445 
01446                 This method creates a new instance of this particular ValueFunction class
01447                 and then loads whatever information is necessary from the file to 
01448                 initialise itself properly. The record read-pointer is left pointing
01449                 at the end of the ValueFunction-saved data so that the caller can continue
01450                 reading their extra bytes of data after loading the ValueFunction.
01451 
01452     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01453 
01454 ******************************************************************************************/
01455 
01456 ValueFunction *ValueFunctionRampL::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01457 {
01458     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01459 
01460     float Value1 = (float) 1.0;
01461     float Value2 = (float) 0.0;
01462 
01463     pInputRecord->ReadFLOAT(&Value1);
01464     pInputRecord->ReadFLOAT(&Value2);
01465 
01466     return(new ValueFunctionRampL((double) Value1, (double) Value2));
01467 }
01468 
01469 
01470 /******************************************************************************************
01471 
01472 >   virtual double ValueFunctionRampL2::GetValue(double Position)
01473 
01474     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01475     Created:    9/10/2000
01476 
01477     Inputs:     Position - A value between 0.0 and 1.0
01478     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01479                 the value of the function at the given Position.
01480 
01481     Purpose:    To read the value of this function at a given position
01482 
01483     Notes:      RampL is a half sine-wave "S" shaped function
01484 
01485 ******************************************************************************************/
01486 
01487 double ValueFunctionRampL2::GetValue(double Position)
01488 {
01489     const double MixValue   = cos((Pi/2.0) + (Position * Pi/2.0)) + 1.0;
01490 
01491     return((MixValue * Value1) + ((1.0 - MixValue) * Value2));
01492 }
01493 
01494 
01495 /******************************************************************************************
01496 
01497 >   virtual INT32 ValueFunctionRampL2::GetMinimumRecursionDepth(void)
01498 
01499     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01500     Created:    9/10/2000
01501 
01502     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01503                 perform at minimum before declaring a line segment 'flat' enough
01504 
01505 ******************************************************************************************/
01506 
01507 INT32 ValueFunctionRampL2::GetMinimumRecursionDepth()
01508 {
01509     return 2;
01510 }
01511 
01512 
01513 /******************************************************************************************
01514 
01515 >   virtual ValueFunction *ValueFunctionRampL::Clone(void)
01516 
01517     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01518     Created:    9/10/2000
01519 
01520     Returns:    NULL if it failed, else an exact copy of this object
01521 
01522     Purpose:    Clone operator. Creates an exact copy of this object
01523 
01524 ******************************************************************************************/
01525 
01526 ValueFunction *ValueFunctionRampL2::Clone(void)
01527 {
01528     ValueFunction *pClone = new ValueFunctionRampL2(Value1, Value2);
01529     return(pClone);
01530 }
01531 
01532 
01533 
01534 /******************************************************************************************
01535 
01536 >   virtual ValueFunction *ValueFunctionRampL::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01537 
01538     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01539     Created:    9/10/2000
01540 
01541     Inputs:     pInputRecord - The file record to read
01542 
01543     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01544                 whatever was saved in that record.
01545 
01546     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01547                 using the WriteFileRecord call. This is called by the base class
01548                 loader routine ReadFileRecord, which finds an appropriate instance
01549                 of a derived class to call to load the data in question.
01550 
01551                 This method creates a new instance of this particular ValueFunction class
01552                 and then loads whatever information is necessary from the file to 
01553                 initialise itself properly. The record read-pointer is left pointing
01554                 at the end of the ValueFunction-saved data so that the caller can continue
01555                 reading their extra bytes of data after loading the ValueFunction.
01556 
01557     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01558 
01559 ******************************************************************************************/
01560 
01561 ValueFunction *ValueFunctionRampL2::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01562 {
01563     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01564 
01565     float Value1 = (float) 1.0;
01566     float Value2 = (float) 0.2;
01567 
01568     pInputRecord->ReadFLOAT(&Value1);
01569     pInputRecord->ReadFLOAT(&Value2);
01570 
01571     return(new ValueFunctionRampL2((double) Value1, (double) Value2));
01572 }
01573 
01574 
01575 
01576 /******************************************************************************************
01577 
01578 >   virtual double ValueFunctionSawTooth::GetValue(double Position)
01579 
01580     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01581     Created:    9/10/2000
01582 
01583     Inputs:     Position - A value between 0.0 and 1.0
01584     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01585                 the value of the function at the given Position.
01586 
01587     Purpose:    To read the value of this function at a given position
01588 
01589     Notes:      SawTooth is a half sine-wave "S" shaped function
01590 
01591 ******************************************************************************************/
01592 
01593 double ValueFunctionSawTooth::GetValue(double Position)
01594 {
01595     if (Position == 1.0)
01596     {
01597         return 0.0;
01598     }
01599     else
01600     {
01601         double Value    = (9.0 * Position) - (floor(9.0 * Position));
01602         return(1.0 - (Value * Value));
01603     }
01604 }
01605 
01606 
01607 
01608 /******************************************************************************************
01609 
01610 >   virtual ValueFunction *ValueFunctionSawTooth::Clone(void)
01611 
01612     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01613     Created:    9/10/2000
01614 
01615     Returns:    NULL if it failed, else an exact copy of this object
01616 
01617     Purpose:    Clone operator. Creates an exact copy of this object
01618 
01619 ******************************************************************************************/
01620 
01621 ValueFunction *ValueFunctionSawTooth::Clone(void)
01622 {
01623     ValueFunction *pClone = new ValueFunctionSawTooth(Value1, Value2);
01624     return(pClone);
01625 }
01626 
01627 
01628 
01629 /******************************************************************************************
01630 
01631 >   virtual INT32 ValueFunctionSawTooth::GetMinimumRecursionDepth(void)
01632 
01633     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01634     Created:    9/10/2000
01635 
01636     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01637                 perform at minimum before declaring a line segment 'flat' enough
01638 
01639 ******************************************************************************************/
01640 
01641 INT32 ValueFunctionSawTooth::GetMinimumRecursionDepth()
01642 {
01643     return 4;
01644 }
01645 
01646 
01647 
01648 /******************************************************************************************
01649 
01650 >   virtual ValueFunction *ValueFunctionSawTooth::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01651 
01652     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01653     Created:    9/10/2000
01654 
01655     Inputs:     pInputRecord - The file record to read
01656 
01657     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01658                 whatever was saved in that record.
01659 
01660     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01661                 using the WriteFileRecord call. This is called by the base class
01662                 loader routine ReadFileRecord, which finds an appropriate instance
01663                 of a derived class to call to load the data in question.
01664 
01665                 This method creates a new instance of this particular ValueFunction class
01666                 and then loads whatever information is necessary from the file to 
01667                 initialise itself properly. The record read-pointer is left pointing
01668                 at the end of the ValueFunction-saved data so that the caller can continue
01669                 reading their extra bytes of data after loading the ValueFunction.
01670 
01671     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01672 
01673 ******************************************************************************************/
01674 
01675 ValueFunction *ValueFunctionSawTooth::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01676 {
01677     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01678 
01679     float Value1 = (float) 1.0;
01680     float Value2 = (float) 0.0;
01681 
01682     pInputRecord->ReadFLOAT(&Value1);
01683     pInputRecord->ReadFLOAT(&Value2);
01684 
01685     return(new ValueFunctionSawTooth((double) Value1, (double) Value2));
01686 }
01687 
01688 
01689 
01690 /******************************************************************************************
01691 
01692 >   virtual double ValueFunctionCurvedSawTooth::GetValue(double Position)
01693 
01694     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01695     Created:    9/10/2000
01696 
01697     Inputs:     Position - A value between 0.0 and 1.0
01698     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01699                 the value of the function at the given Position.
01700 
01701     Purpose:    To read the value of this function at a given position
01702 
01703     Notes:      CurvedSawTooth is a half sine-wave "S" shaped function
01704 
01705 ******************************************************************************************/
01706 
01707 double ValueFunctionPropeller::GetValue(double Position)
01708 {
01709     double Value;
01710 
01711     if (Position < 0.15)
01712     {
01713         //Draw a curved beginning bit...
01714         Position = 1.0 - Position/0.15;
01715         if ( Position>1.0 )
01716             Position = 1.0;
01717         Value = sqrt(1-Position*Position);
01718     }
01719     else
01720     {
01721         if (Position > 0.85)
01722         {
01723             //Draw a curved end bit...
01724             Position = (Position - 0.85) / 0.15;
01725             if ( Position>1.0 )
01726                 Position = 1.0;
01727             Value = sqrt(1-Position*Position);
01728         }
01729         else
01730         {
01731             //Scale Position to be a value between 0 and 1 based on how far through between
01732             //0.15 and 0.85 it is...
01733             Position = (Position - 0.15) / 0.7;
01734             Value = (cos(Position * 2.0 * Pi) + 1.5) * 0.4;
01735         }
01736     }
01737     return Value;
01738 }
01739 
01740 
01741 /******************************************************************************************
01742 
01743 >   virtual INT32 ValueFunctionPropeller::GetMinimumRecursionDepth(void)
01744 
01745     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01746     Created:    9/10/2000
01747 
01748     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01749                 perform at minimum before declaring a line segment 'flat' enough
01750 
01751 ******************************************************************************************/
01752 
01753 INT32 ValueFunctionPropeller::GetMinimumRecursionDepth()
01754 {
01755     return 4;
01756 }
01757 
01758 
01759 /******************************************************************************************
01760 
01761 >   virtual ValueFunction *ValueFunctionPropeller::Clone(void)
01762 
01763     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01764     Created:    9/10/2000
01765 
01766     Returns:    NULL if it failed, else an exact copy of this object
01767 
01768     Purpose:    Clone operator. Creates an exact copy of this object
01769 
01770 ******************************************************************************************/
01771 
01772 ValueFunction *ValueFunctionPropeller::Clone(void)
01773 {
01774     ValueFunction *pClone = new ValueFunctionPropeller(Value1, Value2);
01775     return(pClone);
01776 }
01777 
01778 
01779 
01780 /******************************************************************************************
01781 
01782 >   virtual ValueFunction *ValueFunctionPropeller::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01783 
01784     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01785     Created:    9/10/2000
01786 
01787     Inputs:     pInputRecord - The file record to read
01788 
01789     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01790                 whatever was saved in that record.
01791 
01792     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01793                 using the WriteFileRecord call. This is called by the base class
01794                 loader routine ReadFileRecord, which finds an appropriate instance
01795                 of a derived class to call to load the data in question.
01796 
01797                 This method creates a new instance of this particular ValueFunction class
01798                 and then loads whatever information is necessary from the file to 
01799                 initialise itself properly. The record read-pointer is left pointing
01800                 at the end of the ValueFunction-saved data so that the caller can continue
01801                 reading their extra bytes of data after loading the ValueFunction.
01802 
01803     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01804 
01805 ******************************************************************************************/
01806 
01807 ValueFunction *ValueFunctionPropeller::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01808 {
01809     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01810 
01811     float Value1 = (float) 1.0;
01812     float Value2 = (float) 0.0;
01813 
01814     pInputRecord->ReadFLOAT(&Value1);
01815     pInputRecord->ReadFLOAT(&Value2);
01816 
01817     return(new ValueFunctionPropeller((double) Value1, (double) Value2));
01818 }
01819 
01820 /******************************************************************************************
01821 
01822 >   virtual double ValueFunctionDoubleRampS::GetValue(double Position)
01823 
01824     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01825     Created:    9/10/2000
01826 
01827     Inputs:     Position - A value between 0.0 and 1.0
01828     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01829                 the value of the function at the given Position.
01830 
01831     Purpose:    To read the value of this function at a given position
01832 
01833     Notes:      DoubleRampS is a half sine-wave "S" shaped function
01834 
01835 ******************************************************************************************/
01836 
01837 double ValueFunctionDoubleRampS::GetValue(double Position)
01838 {
01839     const double MixValue   = (cos(Position * 2.0 * Pi) + 1.5) * 0.4;
01840 
01841     return((MixValue * Value1) + ((1.0 - MixValue) * Value2));
01842 }
01843 
01844 
01845 /******************************************************************************************
01846 
01847 >   virtual INT32 ValueFunctionDoubleRampS::GetMinimumRecursionDepth(void)
01848 
01849     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01850     Created:    9/10/2000
01851 
01852     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01853                 perform at minimum before declaring a line segment 'flat' enough
01854 
01855 ******************************************************************************************/
01856 
01857 INT32 ValueFunctionDoubleRampS::GetMinimumRecursionDepth()
01858 {
01859     return 2;
01860 }
01861 
01862 
01863 /******************************************************************************************
01864 
01865 >   virtual ValueFunction *ValueFunctionDoubleRampS::Clone(void)
01866 
01867     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01868     Created:    9/10/2000
01869 
01870     Returns:    NULL if it failed, else an exact copy of this object
01871 
01872     Purpose:    Clone operator. Creates an exact copy of this object
01873 
01874 ******************************************************************************************/
01875 
01876 ValueFunction *ValueFunctionDoubleRampS::Clone(void)
01877 {
01878     ValueFunction *pClone = new ValueFunctionDoubleRampS(Value1, Value2);
01879     return(pClone);
01880 }
01881 
01882 
01883 
01884 /******************************************************************************************
01885 
01886 >   virtual ValueFunction *ValueFunctionDoubleRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01887 
01888     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01889     Created:    9/10/2000
01890 
01891     Inputs:     pInputRecord - The file record to read
01892 
01893     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01894                 whatever was saved in that record.
01895 
01896     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01897                 using the WriteFileRecord call. This is called by the base class
01898                 loader routine ReadFileRecord, which finds an appropriate instance
01899                 of a derived class to call to load the data in question.
01900 
01901                 This method creates a new instance of this particular ValueFunction class
01902                 and then loads whatever information is necessary from the file to 
01903                 initialise itself properly. The record read-pointer is left pointing
01904                 at the end of the ValueFunction-saved data so that the caller can continue
01905                 reading their extra bytes of data after loading the ValueFunction.
01906 
01907     SeeAlso:    ValueFunctionRamp::WriteFileRecord
01908 
01909 ******************************************************************************************/
01910 
01911 ValueFunction *ValueFunctionDoubleRampS::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01912 {
01913     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
01914 
01915     float Value1 = (float) 1.0;
01916     float Value2 = (float) 0.0;
01917 
01918     pInputRecord->ReadFLOAT(&Value1);
01919     pInputRecord->ReadFLOAT(&Value2);
01920 
01921     return(new ValueFunctionDoubleRampS((double) Value1, (double) Value2));
01922 }
01923 
01924 /******************************************************************************************
01925 
01926 >   virtual double ValueFunctionIntestine::GetValue(double Position)
01927 
01928     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01929     Created:    9/10/2000
01930 
01931     Inputs:     Position - A value between 0.0 and 1.0
01932     Returns:    A value (between Value1 and Value2 given in the constructor) representing
01933                 the value of the function at the given Position.
01934 
01935     Purpose:    To read the value of this function at a given position
01936 
01937 ******************************************************************************************/
01938 
01939 double ValueFunctionIntestine::GetValue(double Position)
01940 {
01941     const double MixValue   = ((cos(Position * 20.0 * Pi) + 3.0) / 4.0);
01942     return((MixValue * Value1) + ((1.0 - MixValue) * Value2));
01943 }
01944 
01945 
01946 
01947 /******************************************************************************************
01948 
01949 >   virtual ValueFunction *ValueFunctionIntestine::Clone(void)
01950 
01951     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01952     Created:    9/10/2000
01953 
01954     Returns:    NULL if it failed, else an exact copy of this object
01955 
01956     Purpose:    Clone operator. Creates an exact copy of this object
01957 
01958 ******************************************************************************************/
01959 
01960 ValueFunction *ValueFunctionIntestine::Clone(void)
01961 {
01962     ValueFunction *pClone = new ValueFunctionIntestine(Value1, Value2);
01963     return(pClone);
01964 }
01965 
01966 
01967 /******************************************************************************************
01968 
01969 >   virtual INT32 ValueFunctionIntestine::GetMinimumRecursionDepth(void)
01970 
01971     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
01972     Created:    9/10/2000
01973 
01974     Purpose:    Overriden function to indicate to the path stroker how many recursions to
01975                 perform at minimum before declaring a line segment 'flat' enough
01976 
01977 ******************************************************************************************/
01978 
01979 INT32 ValueFunctionIntestine::GetMinimumRecursionDepth()
01980 {
01981     return 4;
01982 }
01983 
01984 
01985 /******************************************************************************************
01986 
01987 >   virtual ValueFunction *ValueFunctionIntestine::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
01988 
01989     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
01990     Created:    9/10/2000
01991 
01992     Inputs:     pInputRecord - The file record to read
01993 
01994     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
01995                 whatever was saved in that record.
01996 
01997     Purpose:    Loads a ValueFunction object from a record which was saved into a file
01998                 using the WriteFileRecord call. This is called by the base class
01999                 loader routine ReadFileRecord, which finds an appropriate instance
02000                 of a derived class to call to load the data in question.
02001 
02002                 This method creates a new instance of this particular ValueFunction class
02003                 and then loads whatever information is necessary from the file to 
02004                 initialise itself properly. The record read-pointer is left pointing
02005                 at the end of the ValueFunction-saved data so that the caller can continue
02006                 reading their extra bytes of data after loading the ValueFunction.
02007 
02008     SeeAlso:    ValueFunctionRamp::WriteFileRecord
02009 
02010 ******************************************************************************************/
02011 
02012 ValueFunction *ValueFunctionIntestine::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02013 {
02014     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
02015 
02016     float Value1 = (float) 1.0;
02017     float Value2 = (float) 0.0;
02018 
02019     pInputRecord->ReadFLOAT(&Value1);
02020     pInputRecord->ReadFLOAT(&Value2);
02021 
02022     return(new ValueFunctionIntestine((double) Value1, (double) Value2));
02023 }
02024 
02025 /******************************************************************************************
02026 
02027 >   virtual double ValueFunctionDecay::GetValue(double Position)
02028 
02029     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02030     Created:    9/10/2000
02031 
02032     Inputs:     Position - A value between 0.0 and 1.0
02033     Returns:    A value (between Value1 and Value2 given in the constructor) representing
02034                 the value of the function at the given Position.
02035 
02036     Purpose:    To read the value of this function at a given position
02037 
02038 ******************************************************************************************/
02039 
02040 double ValueFunctionDecay::GetValue(double Position)
02041 {
02042     const double MixValue   = (1.0 - Position) * ((cos(Position * 20.0 * Pi) + 3.0) / 4.0);
02043     return MixValue;
02044 }
02045 
02046 
02047 
02048 /******************************************************************************************
02049 
02050 >   virtual ValueFunction *ValueFunctionDecay::Clone(void)
02051 
02052     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02053     Created:    9/10/2000
02054 
02055     Returns:    NULL if it failed, else an exact copy of this object
02056 
02057     Purpose:    Clone operator. Creates an exact copy of this object
02058 
02059 ******************************************************************************************/
02060 
02061 ValueFunction *ValueFunctionDecay::Clone(void)
02062 {
02063     ValueFunction *pClone = new ValueFunctionDecay(Value1, Value2);
02064     return(pClone);
02065 }
02066 
02067 /******************************************************************************************
02068 
02069 >   virtual INT32 ValueFunctionDecay::GetMinimumRecursionDepth(void)
02070 
02071     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
02072     Created:    9/10/2000
02073 
02074     Purpose:    Overriden function to indicate to the path stroker how many recursions to
02075                 perform at minimum before declaring a line segment 'flat' enough
02076 
02077 ******************************************************************************************/
02078 
02079 
02080 INT32 ValueFunctionDecay::GetMinimumRecursionDepth()
02081 {
02082     return 4;
02083 }
02084 
02085 
02086 /******************************************************************************************
02087 
02088 >   virtual ValueFunction *ValueFunctionDecay::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02089 
02090     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02091     Created:    9/10/2000
02092 
02093     Inputs:     pInputRecord - The file record to read
02094 
02095     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
02096                 whatever was saved in that record.
02097 
02098     Purpose:    Loads a ValueFunction object from a record which was saved into a file
02099                 using the WriteFileRecord call. This is called by the base class
02100                 loader routine ReadFileRecord, which finds an appropriate instance
02101                 of a derived class to call to load the data in question.
02102 
02103                 This method creates a new instance of this particular ValueFunction class
02104                 and then loads whatever information is necessary from the file to 
02105                 initialise itself properly. The record read-pointer is left pointing
02106                 at the end of the ValueFunction-saved data so that the caller can continue
02107                 reading their extra bytes of data after loading the ValueFunction.
02108 
02109     SeeAlso:    ValueFunctionRamp::WriteFileRecord
02110 
02111 ******************************************************************************************/
02112 
02113 ValueFunction *ValueFunctionDecay::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02114 {
02115     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
02116 
02117     float Value1 = (float) 1.0;
02118     float Value2 = (float) 0.0;
02119 
02120     pInputRecord->ReadFLOAT(&Value1);
02121     pInputRecord->ReadFLOAT(&Value2);
02122 
02123     return(new ValueFunctionDecay((double) Value1, (double) Value2));
02124 }
02125 
02126 
02127 
02128 /******************************************************************************************
02129 
02130 >   virtual double ValueFunctionBevelEnds::GetValue(double Position)
02131 
02132     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02133     Created:    9/10/2000
02134 
02135     Inputs:     Position - A value between 0.0 and 1.0
02136     Returns:    A value (between Value1 and Value2 given in the constructor) representing
02137                 the value of the function at the given Position.
02138 
02139     Purpose:    To read the value of this function at a given position
02140 
02141     Notes:      Blobby is a half sine-wave "S" shaped function
02142 
02143 ******************************************************************************************/
02144 
02145 double ValueFunctionBevelEnds::GetValue(double Position)
02146 {
02147     double Value;
02148 
02149     if (Position == 1.0)
02150     {
02151         Value = 0.0;
02152     }
02153     else
02154     {
02155         if (Position < 0.15)
02156         {
02157             Position = Position / 0.15;
02158             Value = Position;
02159         }
02160         else
02161         {
02162             if (Position > 0.85)
02163             {
02164                 Position = (Position - 0.85) / 0.15;
02165                 Value = 1.0 - Position;
02166             }
02167             else
02168             {
02169                 Value = 1.0;
02170             }
02171         }
02172     }
02173 
02174     return Value;
02175 }
02176 
02177 
02178 
02179 /******************************************************************************************
02180 
02181 >   virtual ValueFunction *ValueFunctionBevelEnds::Clone(void)
02182 
02183     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02184     Created:    9/10/2000
02185 
02186     Returns:    NULL if it failed, else an exact copy of this object
02187 
02188     Purpose:    Clone operator. Creates an exact copy of this object
02189 
02190 ******************************************************************************************/
02191 
02192 ValueFunction *ValueFunctionBevelEnds::Clone(void)
02193 {
02194     ValueFunction *pClone = new ValueFunctionBevelEnds(Value1, Value2);
02195     return(pClone);
02196 }
02197 
02198 
02199 /******************************************************************************************
02200 
02201 >   virtual INT32 ValueFunctionBevelEnds::GetMinimumRecursionDepth(void)
02202 
02203     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
02204     Created:    9/10/2000
02205 
02206     Purpose:    Overriden function to indicate to the path stroker how many recursions to
02207                 perform at minimum before declaring a line segment 'flat' enough
02208 
02209 ******************************************************************************************/
02210 
02211 INT32 ValueFunctionBevelEnds::GetMinimumRecursionDepth()
02212 {
02213     return 4;
02214 }
02215 
02216 
02217 /******************************************************************************************
02218 
02219 >   virtual ValueFunction *ValueFunctionBevelEnds::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02220 
02221     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02222     Created:    9/10/2000
02223 
02224     Inputs:     pInputRecord - The file record to read
02225 
02226     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
02227                 whatever was saved in that record.
02228 
02229     Purpose:    Loads a ValueFunction object from a record which was saved into a file
02230                 using the WriteFileRecord call. This is called by the base class
02231                 loader routine ReadFileRecord, which finds an appropriate instance
02232                 of a derived class to call to load the data in question.
02233 
02234                 This method creates a new instance of this particular ValueFunction class
02235                 and then loads whatever information is necessary from the file to 
02236                 initialise itself properly. The record read-pointer is left pointing
02237                 at the end of the ValueFunction-saved data so that the caller can continue
02238                 reading their extra bytes of data after loading the ValueFunction.
02239 
02240     SeeAlso:    ValueFunctionRamp::WriteFileRecord
02241 
02242 ******************************************************************************************/
02243 
02244 ValueFunction *ValueFunctionBevelEnds::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02245 {
02246     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
02247 
02248     float Value1 = (float) 1.0;
02249     float Value2 = (float) 0.0;
02250 
02251     pInputRecord->ReadFLOAT(&Value1);
02252     pInputRecord->ReadFLOAT(&Value2);
02253 
02254     return(new ValueFunctionBevelEnds((double) Value1, (double) Value2));
02255 }
02256 
02257 
02258 
02259 
02260 
02262 // ValueFunctionBlip and derived classes
02264 
02265 /******************************************************************************************
02266 
02267 >   ValueFunctionBlip::ValueFunctionBlip(double Value)
02268 
02269     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02270     Created:    1/2/97
02271 
02272     Inputs:     MaxPosition - The position at which the function should reach
02273                               its maximum value. Normally this is at 0.5, but
02274                               for asymmetrical blips, values like 0.2 are better
02275     Purpose:    Constructor
02276 
02277 ******************************************************************************************/
02278 
02279 ValueFunctionBlip::ValueFunctionBlip(double MaxPosition)
02280 {
02281     ERROR3IF(MaxPosition <= 0.0 || MaxPosition >= 1.0, "Silly MaxPosition value");
02282     MaxPos = MaxPosition;
02283 }
02284 
02285 
02286 
02287 /******************************************************************************************
02288 
02289 >   virtual double ValueFunctionBlip::GetValue(double Position)
02290 
02291     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02292     Created:    1/2/97
02293 
02294     Inputs:     Position - A value between 0.0 and 1.0
02295     Returns:    A value representing the value of the function at the given Position.
02296 
02297     Purpose:    To read the value of this function at a given position
02298 
02299     Notes:      This Blip is a 360 degree sine wave from 0.0 to 1.0 and back again.
02300                 However, because the midpoint is adjustable, it is a piecewise function
02301 
02302 ******************************************************************************************/
02303 
02304 double ValueFunctionBlip::GetValue(double Position)
02305 {
02306     double Value;
02307     if (Position < MaxPos)
02308     {
02309         Position /= MaxPos;
02310         Value = sin(Position * (Pi / 2.0));
02311     }
02312     else
02313     {
02314         Position = (Position - MaxPos) / (1.0 - MaxPos);
02315         Value = cos(Position * (Pi / 2.0));
02316     }
02317 
02318     return(Value);
02319 }
02320 
02321 
02322 
02323 /******************************************************************************************
02324 
02325 >   virtual ValueFunction *ValueFunctionBlip::Clone(void)
02326 
02327     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02328     Created:    1/2/97
02329 
02330     Returns:    NULL if it failed, else an exact copy of this object
02331 
02332     Purpose:    Clone operator. Creates an exact copy of this object
02333 
02334 ******************************************************************************************/
02335 
02336 ValueFunction *ValueFunctionBlip::Clone(void)
02337 {
02338     ValueFunctionBlip *pClone = CreateInstance();
02339 
02340     if (pClone != NULL)
02341         pClone->MaxPos = MaxPos;
02342 
02343     return(pClone);
02344 }
02345 
02346 
02347 
02348 /******************************************************************************************
02349 
02350 >   virtual BOOL ValueFunctionBlip::IsDifferent(ValueFunction *Other)
02351 
02352     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02353     Created:    1/2/97
02354 
02355     Inputs:     pOther - Another ValueFunction object to compare this one to
02356 
02357     Returns:    TRUE if the objects are considered different,
02358                 FALSE if they are considered identical
02359 
02360     Purpose:    Comparator.
02361                 Determines if 2 different ValueFunction objects are considered
02362                 different.
02363 
02364     Notes:      Calls the base class to see if they are different classes,
02365                 and then compares identical classes by checking member vars
02366 
02367 ******************************************************************************************/
02368 
02369 BOOL ValueFunctionBlip::IsDifferent(ValueFunction *pOther)
02370 {
02371     if (ValueFunction::IsDifferent(pOther))
02372         return(TRUE);
02373     
02374     // Both objects are instances of this class, so compare them more carefully
02375     return(MaxPos != ((ValueFunctionBlip *)pOther)->MaxPos);
02376 }
02377 
02378 
02379 
02380 /******************************************************************************************
02381 
02382 >   virtual CamelotFileRecord *ValueFunctionBlip::WriteFileRecord(INT32 RecordTag,
02383                                             INT32 ExtraBytes, BaseCamelotFilter *pFilter)
02384 
02385     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02386     Created:    1/2/97
02387 
02388     Inputs:     RecordTag   - the tag to write this record under
02389                 ExtraBytes  - The number of extra bytes of information the caller
02390                               will write into the record after caling this function
02391                               (Space for this many extra bytes will be reserved by
02392                               this function when it creates the new file record)
02393                               This may be 0 or more bytes.
02394                 pFilter     - The filter to write to
02395 
02396     Returns:    NULL if it failed, else a pointer to a record which saves the state
02397                 of this valueFunction object. Once the caller has written the record,
02398                 they MUST DELETE it.
02399 
02400     Purpose:    Saves a ValueFunction object to a Xara file.
02401                 This function will create a new variable-sized record with the given
02402                 record tag, and will write out whatever data is needed to save this
02403                 ValueFunction's state to the file.
02404                 
02405                 "ExtraBytes" bytes will be added to the record size to reserve space
02406                 at the end of the record for the caller to add their own data. This
02407                 is to allow ValueFunctions to be saved embedded in other object's
02408                 record structures (e.g. inside different types of attributes).
02409 
02410                 All ValueFunction record data has 3 sections, whiich are recorded as follows:
02411                 1. ValueFunction header, identifying which type of VF is being saved
02412                         INT32 ValueFunctionUniqueID     (4 bytes)
02413                 2. Derived-class-data (0 or more bytes). This particular class adds:
02414                         float MaxPosition               (4 bytes)
02415                 3. Caller data. This is written by the caller to the returned record
02416                    object. This data must be ExtraBytes (0 or more) bytes in length.
02417 
02418     SeeAlso:    ValueFunctionBlip::CreateAndReadFileRecord
02419 
02420 ******************************************************************************************/
02421 
02422 CamelotFileRecord *ValueFunctionBlip::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes,
02423                                                             BaseCamelotFilter *pFilter)
02424 {
02425     ERROR3IF(pFilter == NULL, "Illegal NULL param");
02426     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord");
02427 
02428     // Calculate how many bytes of information this VF will write. We do not include
02429     // the header info written by the base class or the ExtraInfo desired by the caller -
02430     // the base class adds all that in for us.
02431     const INT32 MyRecordSize = 4;
02432 
02433     // Create an appropriate record, and write our data to it
02434     CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter);
02435 
02436     if (pRec != NULL)
02437     {
02438         // Write out our ValueFunction's specific data. If it fails, then we'll return NULL
02439         if (!pRec->WriteFLOAT((float)MaxPos))
02440         {
02441             delete pRec;
02442             pRec = NULL;
02443         }
02444     }
02445 
02446     return(pRec);
02447 }
02448 
02449 
02450 
02451 /******************************************************************************************
02452 
02453 >   virtual ValueFunction *ValueFunctionBlip::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02454 
02455     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02456     Created:    1/2/97
02457 
02458     Inputs:     pInputRecord - The file record to read
02459 
02460     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
02461                 whatever was saved in that record.
02462 
02463     Purpose:    Loads a ValueFunction object from a record which was saved into a file
02464                 using the WriteFileRecord call. This is called by the base class
02465                 loader routine ReadFileRecord, which finds an appropriate instance
02466                 of a derived class to call to load the data in question.
02467 
02468                 This method creates a new instance of this particular ValueFunction class
02469                 and then loads whatever information is necessary from the file to 
02470                 initialise itself properly. The record read-pointer is left pointing
02471                 at the end of the ValueFunction-saved data so that the caller can continue
02472                 reading their extra bytes of data after loading the ValueFunction.
02473 
02474     SeeAlso:    ValueFunctionBlip::WriteFileRecord;
02475                 ValueFunctionBlip::ReadFileRecord
02476 
02477 ******************************************************************************************/
02478 
02479 ValueFunction *ValueFunctionBlip::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
02480 {
02481     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
02482 
02483     float MaxPosition = (float)0.5;
02484     pInputRecord->ReadFLOAT(&MaxPosition);
02485 
02486     ValueFunctionBlip *pBlip = CreateInstance();
02487     if (pBlip != NULL)
02488         pBlip->MaxPos = MaxPosition;
02489 
02490     return(pBlip);
02491 }
02492 
02493 
02494 
02495 /******************************************************************************************
02496 
02497 >   virtual ValueFunctionBlip *ValueFunctionBlip::CreateInstance(void)
02498 
02499     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02500     Created:    1/2/97
02501 
02502     Returns:    NULL if it failed, else a pointer to new ValueFunctionBlip object of
02503                 the same type as "this" one. Used to allow derived Blip classes to
02504                 use all the base class code, and merely override the GetValue method.
02505 
02506     Purpose:    Creates a new blank object of the same type as this one. Internal
02507                 function used in ValueFunctionBlip & ValueFunctionBlipS.
02508 
02509     Notes:      Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord,
02510                 as this is the only action in those functions that depends on the type
02511                 of the class that is being used
02512 
02513 ******************************************************************************************/
02514 
02515 ValueFunctionBlip *ValueFunctionBlip::CreateInstance(void)
02516 {   
02517     return(new ValueFunctionBlip);
02518 }
02519 
02520 
02521 
02522 
02523 
02524 
02525 
02526 
02527 /******************************************************************************************
02528 
02529 >   virtual double ValueFunctionTeardrop::GetValue(double Position)
02530 
02531     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02532     Created:    1/2/97
02533 
02534     Inputs:     Position - A value between 0.0 and 1.0
02535     Returns:    A value representing the value of the function at the given Position.
02536 
02537     Purpose:    To read the value of this function at a given position
02538 
02539 ******************************************************************************************/
02540 
02541 double ValueFunctionTeardrop::GetValue(double Position)
02542 {
02543     double Value;
02544     if (Position < MaxPos)
02545     {
02546         Position = 1.0 - Position/MaxPos;
02547         if ( Position>1.0 )
02548             Position = 1.0;
02549         Value = sqrt(1-Position*Position);
02550     }
02551     else
02552     {
02553         Position = (Position - MaxPos) / (1.0 - MaxPos);
02554         Value = (cos( Position * Pi) + 1.0) / 2.0;
02555     }
02556 
02557     return Value;
02558 }
02559 
02560 
02561 
02562 /******************************************************************************************
02563 
02564 >   virtual ValueFunctionBlip *ValueFunctionTeardrop::CreateInstance(void)
02565 
02566     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02567     Created:    1/2/97
02568 
02569     Returns:    NULL if it failed, else a pointer to new ValueFunctionTeardrop object of
02570                 the same type as "this" one. Used to allow derived Teardrop classes to
02571                 use all the base class code, and merely override the GetValue method.
02572 
02573     Purpose:    Creates a new blank object of the same type as this one. Internal
02574                 function used in ValueFunctionTeardrop & ValueFunctionTeardropS.
02575 
02576     Notes:      Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord,
02577                 as this is the only action in those functions that depends on the type
02578                 of the class that is being used
02579 
02580 ******************************************************************************************/
02581 
02582 ValueFunctionBlip *ValueFunctionTeardrop::CreateInstance(void)
02583 {   
02584     return(new ValueFunctionTeardrop);
02585 }
02586 
02587 
02588 /******************************************************************************************
02589 
02590 >   virtual double ValueFunctionTeardropCurvedEnd::GetValue(double Position)
02591 
02592     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02593     Created:    9/10/2000
02594 
02595     Inputs:     Position - A value between 0.0 and 1.0
02596     Returns:    A value representing the value of the function at the given Position.
02597 
02598     Purpose:    To read the value of this function at a given position
02599 
02600 ******************************************************************************************/
02601 
02602 double ValueFunctionTeardropCurvedEnd::GetValue(double Position)
02603 {
02604     double Value;
02605     if (Position < 0.2)
02606     {
02607         Position = 1.0 - Position/0.2;
02608         if ( Position>1.0 )
02609             Position = 1.0;
02610         Value = sqrt(1-Position*Position);
02611     }
02612     else
02613     {
02614         Position = (Position - 0.2) / 0.8;
02615         Value = sqrt(1.0 - Position);
02616     }
02617 
02618 /*      if (Position > 0.9)
02619         {
02620             Position = (Position - 0.9) / 0.1;
02621             Value = 0.4 * (cos(asin(Position)));
02622         }
02623         else
02624         {
02625             Position = (Position - 0.2) / 0.7;
02626             Value = ((1.0 - (Position * Position)) * 0.6) + 0.4;
02627         }
02628     }
02629 */
02630     return(Value);
02631 }
02632 
02633 
02634 /******************************************************************************************
02635 
02636 >   virtual INT32 ValueFunctionTeardropCurvedEnd::GetMinimumRecursionDepth(void)
02637 
02638     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
02639     Created:    9/10/2000
02640 
02641     Purpose:    Overriden function to indicate to the path stroker how many recursions to
02642                 perform at minimum before declaring a line segment 'flat' enough
02643 
02644 ******************************************************************************************/
02645 
02646 INT32 ValueFunctionTeardropCurvedEnd::GetMinimumRecursionDepth()
02647 {
02648     return 2;
02649 }
02650 
02651 
02652 /******************************************************************************************
02653 
02654 >   virtual ValueFunctionBlip *ValueFunctionTeardropCurvedEnd::CreateInstance(void)
02655 
02656     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com> from Jason
02657     Created:    9/10/2000
02658 
02659     Returns:    NULL if it failed, else a pointer to new ValueFunctionTeardrop object of
02660                 the same type as "this" one. Used to allow derived Teardrop classes to
02661                 use all the base class code, and merely override the GetValue method.
02662 
02663     Purpose:    Creates a new blank object of the same type as this one. Internal
02664                 function used in ValueFunctionTeardrop & ValueFunctionTeardropS.
02665 
02666     Notes:      Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord,
02667                 as this is the only action in those functions that depends on the type
02668                 of the class that is being used
02669 
02670 ******************************************************************************************/
02671 
02672 ValueFunctionBlip *ValueFunctionTeardropCurvedEnd::CreateInstance(void)
02673 {   
02674     return(new ValueFunctionTeardropCurvedEnd);
02675 }
02676 
02677 
02678 
02679 
02680 
02681 
02682 
02683 
02684 /******************************************************************************************
02685 
02686 >   virtual double ValueFunctionEllipse::GetValue(double Position)
02687 
02688     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02689     Created:    1/2/97
02690 
02691     Inputs:     Position - A value between 0.0 and 1.0
02692     Returns:    A value representing the value of the function at the given Position.
02693 
02694     Purpose:    To read the value of this function at a given position
02695 
02696 ******************************************************************************************/
02697 
02698 double ValueFunctionEllipse::GetValue(double Position)
02699 {
02700     if (Position < MaxPos)
02701         Position = 1.0 - Position/MaxPos;
02702     else
02703         Position = (Position - MaxPos) / (1.0 - MaxPos);
02704     if ( Position>1.0 )
02705         Position = 1.0;
02706     return sqrt(1-Position*Position);
02707 }
02708 
02709 
02710 
02711 /******************************************************************************************
02712 
02713 >   virtual ValueFunctionBlip *ValueFunctionEllipse::CreateInstance(void)
02714 
02715     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02716     Created:    1/2/97
02717 
02718     Returns:    NULL if it failed, else a pointer to new ValueFunctionEllipse object of
02719                 the same type as "this" one. Used to allow derived Ellipse classes to
02720                 use all the base class code, and merely override the GetValue method.
02721 
02722     Purpose:    Creates a new blank object of the same type as this one. Internal
02723                 function used in ValueFunctionEllipse & ValueFunctionEllipseS.
02724 
02725     Notes:      Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord,
02726                 as this is the only action in those functions that depends on the type
02727                 of the class that is being used
02728 
02729 ******************************************************************************************/
02730 
02731 ValueFunctionBlip *ValueFunctionEllipse::CreateInstance(void)
02732 {   
02733     return(new ValueFunctionEllipse);
02734 }
02735 
02736 
02737 
02738 
02739 
02740 
02741 
02742 
02743 
02744 /******************************************************************************************
02745 
02746 >   virtual double ValueFunctionThumbtack::GetValue(double Position)
02747 
02748     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02749     Created:    26/2/97
02750 
02751     Inputs:     Position - A value between 0.0 and 1.0
02752     Returns:    A value representing the value of the function at the given Position.
02753 
02754     Purpose:    To read the value of this function at a given position
02755 
02756 ******************************************************************************************/
02757 
02758 double ValueFunctionThumbtack::GetValue(double Position)
02759 {
02760     if (Position < MaxPos)
02761         Position = Position / MaxPos;
02762     else
02763         Position = 1.0 - ((Position - MaxPos) / (1.0 - MaxPos));
02764 
02765     if ( Position>1.0 )
02766         Position = 1.0;
02767     return 1.0 - sqrt(1-Position*Position);
02768 }
02769 
02770 
02771 
02772 /******************************************************************************************
02773 
02774 >   virtual ValueFunctionBlip *ValueFunctionThumbtack::CreateInstance(void)
02775 
02776     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02777     Created:    26/2/97
02778 
02779     Returns:    NULL if it failed, else a pointer to new ValueFunctionThumbtack object of
02780                 the same type as "this" one. Used to allow derived Thumbtack classes to
02781                 use all the base class code, and merely override the GetValue method.
02782 
02783     Purpose:    Creates a new blank object of the same type as this one. Internal
02784                 function used in ValueFunctionThumbtack & ValueFunctionThumbtackS.
02785 
02786     Notes:      Called by ValueFunctionBlip::Clone and CreateAndReadFileRecord,
02787                 as this is the only action in those functions that depends on the type
02788                 of the class that is being used
02789 
02790 ******************************************************************************************/
02791 
02792 ValueFunctionBlip *ValueFunctionThumbtack::CreateInstance(void)
02793 {   
02794     return(new ValueFunctionThumbtack);
02795 }
02796 
02797 
02798 
02799 
02800 
02801 
02803 // ValueFunctionPressure classes
02805 
02806 
02807 /******************************************************************************************
02808 
02809 >   ValueFunctionPressure::ValueFunctionPressure()
02810 
02811     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02812     Created:    20/1/97
02813 
02814     Purpose:    Constructor
02815                 Pressure functions store a table of recorded pressure values and 
02816                 return curve-interpolated pressure values on demand.
02817 
02818 ******************************************************************************************/
02819 
02820 ValueFunctionPressure::ValueFunctionPressure()
02821 {
02822     pArray      = NULL;
02823     ArraySize   = 0;
02824     NextFree    = 0;
02825 }
02826 
02827 
02828 
02829 /******************************************************************************************
02830 
02831 >   ValueFunctionPressure::~ValueFunctionPressure()
02832 
02833     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02834     Created:    20/1/97
02835 
02836     Purpose:    Destructor
02837 
02838 ******************************************************************************************/
02839 
02840 ValueFunctionPressure::~ValueFunctionPressure()
02841 {
02842     if (pArray != NULL)
02843         CCFree(pArray);
02844 }
02845 
02846 
02847 
02848 /******************************************************************************************
02849 
02850 >   virtual double ValueFunctionPressure::GetValue(double Position)
02851 
02852     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02853     Created:    20/1/97
02854 
02855     Inputs:     Position - A value between 0.0 and 1.0
02856     Returns:    A value representing the recorded pressure at the given Position.
02857 
02858     Purpose:    To read the value of this function at a given position
02859 
02860     Notes:      This determines the 2 closest position values for which pressure
02861                 information was recorded, and interpolates the values by "fitting a
02862                 curve" through the points.
02863 
02864                 The "curve" may be improved in future, but is currently a simple
02865                 linear interpolation.
02866 
02867                 ****!!!!TODO: This should cache the last array index it was asked for,
02868                 and start the search from that index, as we usually ask for values for
02869                 sequential, close, position values, and this will vastly reduce the
02870                 searching overhead in most cases. Note that we may step through
02871                 positions in both positive & negative directions, so it will have
02872                 to handle this carefully.
02873 
02874 ******************************************************************************************/
02875 
02876 double ValueFunctionPressure::GetValue(double Position)
02877 {
02878     // No entries have been recorded!
02879     if (NextFree < 1)
02880         return(0.0);
02881 
02882     // If the position is outside the range in our table, return the closest entry
02883     if (Position <= pArray[0].Position)
02884         return(pArray[0].Pressure);
02885 
02886     if (Position >= pArray[NextFree-1].Position)
02887         return(pArray[NextFree-1].Pressure);
02888 
02889     // Search to find the closest 2 array entries to the position
02890     // We assume the array fills the 0.0 to 1.0 range, so we search from the closest
02891     // "end" of the array to halve the average search time.
02892     INT32 i;
02893     if (Position >= 0.5)
02894     {
02895         i = NextFree;
02896         while (i > 1 && Position < pArray[i-1].Position)
02897             i--;
02898     }
02899     else
02900     {
02901         i = 1;
02902         while (i < NextFree && Position > pArray[i].Position)
02903             i++;
02904     }
02905 
02906     ERROR3IF(i < 1 || i >= NextFree, "I've screwed up the scanning loop code");
02907 
02908     // Otherwise, the position lies between array elements [i-1] and [i], so we
02909     // interpolate between these positions
02910     ERROR3IF((pArray[i].Position - pArray[i-1].Position) <= 0.0, "Pressure array is non-ascending!");
02911     const double MixValue = (Position - pArray[i-1].Position) /
02912                             (pArray[i].Position - pArray[i-1].Position);
02913 
02914     return((MixValue * pArray[i].Pressure) + ((1.0 - MixValue) * pArray[i-1].Pressure));
02915 }
02916 
02917 
02918 
02919 /******************************************************************************************
02920 
02921 >   virtual ValueFunction *ValueFunctionPressure::Clone(void)
02922 
02923     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02924     Created:    20/1/97
02925 
02926     Returns:    NULL if it failed, else an exact copy of this object
02927 
02928     Purpose:    Clone operator. Creates an exact copy of this object
02929 
02930 ******************************************************************************************/
02931 
02932 ValueFunction *ValueFunctionPressure::Clone(void)
02933 {
02934     // Create another object of this type
02935     ValueFunctionPressure *pClone = CreateInstance();
02936 
02937     if (pClone != NULL)
02938     {
02939         // If that worked, make it allocate an array large enough to hold a copy of
02940         // our data, and memcpy the array across.
02941         if (pClone->ExpandArray(NextFree))
02942         {
02943             // We only copy the used array entries so the clone will have no wasted space in it
02944             memcpy(pClone->pArray, pArray, NextFree * sizeof(VFPressureRecord));
02945             pClone->NextFree  = NextFree;
02946             pClone->ArraySize = NextFree;
02947         }
02948     }
02949 
02950     return(pClone);
02951 }
02952 
02953 
02954 
02955 /******************************************************************************************
02956 
02957 >   virtual BOOL ValueFunctionPressure::IsDifferent(ValueFunction *Other)
02958 
02959     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
02960     Created:    20/1/97
02961 
02962     Inputs:     pOther - Another ValueFunction object to compare this one to
02963 
02964     Returns:    TRUE if the objects are considered different,
02965                 FALSE if they are considered identical
02966 
02967     Purpose:    Comparator.
02968                 Determines if 2 different ValueFunction objects are considered
02969                 different.
02970 
02971     Notes:      Calls the base class to see if they are different classes,
02972                 and then compares identical classes by checking member vars
02973 
02974 ******************************************************************************************/
02975 
02976 BOOL ValueFunctionPressure::IsDifferent(ValueFunction *pOther)
02977 {
02978     if (ValueFunction::IsDifferent(pOther))
02979         return(TRUE);
02980     
02981     // Both objects are instances of this class, so compare them more carefully
02982     ValueFunctionPressure *pPressure = (ValueFunctionPressure *)pOther;
02983     if (NextFree != pPressure->NextFree)
02984         return(TRUE);                   // Don't have same number of entries
02985 
02986     // Now compare the entire array
02987     for (INT32 i = 0; i < NextFree; i++)
02988     {
02989         if (pArray[i].Position != pPressure->pArray[i].Position ||
02990             pArray[i].Pressure != pPressure->pArray[i].Pressure)
02991         {
02992             return(TRUE);
02993         }
02994     }
02995 
02996     // Cor. They must be the same!
02997     return(FALSE);
02998 }
02999 
03000 
03001 
03002 /******************************************************************************************
03003 
03004 >   BOOL ValueFunctionPressure::AddPressure(float Position, BYTE PressureValue)
03005 
03006     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03007     Created:    20/1/97
03008 
03009     Inputs:     Position - A number representing distance along the path of this point
03010                 (Normally this would be between 0.0 and 1.0, but you can temporarily
03011                 use positions between 0.0 and any positive value and then call
03012                 NormalisePositions if this is more convenient while building the table)
03013 
03014                 NOTE: Each added pressure value must be a positive number, and must
03015                 be greater than the last in order to be recorded. Illegal values
03016                 will be discarded.
03017 
03018                 PressureValue - The pressure value to record for this position
03019 
03020     Returns:    FALSE if memory was unavailable
03021                 TRUE if it was happy (even if it discarded the value)
03022 
03023     Purpose:    Adds a pressure record to the ValueFunction table. 
03024 
03025 ******************************************************************************************/
03026 
03027 BOOL ValueFunctionPressure::AddPressure(float Position, float PressureValue)
03028 {
03029     ERROR3IF(PressureValue < 0.0 || PressureValue > 1.0, "Illegal pressure value");
03030     ERROR3IF(Position < 0.0, "Illegal (negative) position value");
03031 
03032     // Make sure there's plenty of room for new entries
03033     if (NextFree >= ArraySize && !ExpandArray(ArraySize + 32))
03034         return(FALSE);
03035 
03036     // Only record the value if the position has advanced. Error if the position has
03037     // gone retrograde, but quietly dismiss equal positions.
03038     ERROR3IF(NextFree > 0 && Position < pArray[NextFree-1].Position,
03039                 "AddPressure - pressure values must be ascending");
03040     if (NextFree > 0 && Position <= pArray[NextFree-1].Position)
03041         return(TRUE);
03042 
03043     // And write this entry
03044     pArray[NextFree].Position = Position;
03045     pArray[NextFree].Pressure = PressureValue;
03046     NextFree++;
03047 
03048     return(TRUE);
03049 }
03050 
03051 
03052 
03053 /******************************************************************************************
03054 
03055 >   void ValueFunctionPressure::NormalisePositions(void)
03056 
03057     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03058     Created:    20/1/97
03059 
03060     Purpose:    Normalises all positions in the table to lie within a 0.0 to 1.0 range,
03061                 by dividing them by the last element position value. (i.e. it assumes that
03062                 the last element in the array will have the largest Position value)
03063 
03064 ******************************************************************************************/
03065 
03066 void ValueFunctionPressure::NormalisePositions(void)
03067 {
03068     // If fewer than 1 entries, or no array, then there's nothing to do
03069     if (pArray == NULL || NextFree < 1)
03070         return;
03071 
03072     // Find the maximum value, and baulk if it would cause a divide by zero.
03073     if (pArray[NextFree-1].Position <= 0.0)
03074     {
03075         ERROR3("Max position in table is zero or negative - normalisation failed");
03076         return;
03077     }
03078 
03079     float RMaxPosition = 1.0/pArray[NextFree-1].Position;
03080     for (INT32 i = 0; i < NextFree; i++)
03081         pArray[i].Position *= RMaxPosition;
03082 }
03083 
03084 
03085 
03086 /******************************************************************************************
03087 
03088 >   BOOL ValueFunctionPressure::ExpandArray(INT32 NewSize)
03089 
03090     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03091     Created:    20/1/97
03092 
03093     Inputs:     NewSize - The number of array entries desired.
03094 
03095     Returns:    FALSE if memory was unavailable
03096 
03097     Purpose:    Ensures that the pressure storage array has no fewer than NewSize entries.
03098 
03099     Notes:      For efficiency, unused array entries are always left uninitialised
03100 
03101 ******************************************************************************************/
03102 
03103 BOOL ValueFunctionPressure::ExpandArray(INT32 NewSize)
03104 {
03105     if (NewSize <= ArraySize)
03106         return(TRUE);           // That was easy!
03107 
03108     VFPressureRecord *pNewArray = NULL;
03109 
03110     if (pArray == NULL)
03111         pNewArray = (VFPressureRecord *) CCMalloc(NewSize * sizeof(VFPressureRecord));
03112     else
03113         pNewArray = (VFPressureRecord *) CCRealloc(pArray, NewSize * sizeof(VFPressureRecord));
03114 
03115     if (pNewArray == NULL)
03116         return(FALSE);
03117 
03118     // We succeeded, so remember the new address & size
03119     pArray = pNewArray;
03120     ArraySize = NewSize;
03121 
03122     return(TRUE);
03123 }
03124 
03125 
03126 
03127 /******************************************************************************************
03128 
03129 >   virtual CamelotFileRecord *ValueFunctionPressure::WriteFileRecord(INT32 RecordTag,
03130                                             INT32 ExtraBytes, BaseCamelotFilter *pFilter)
03131 
03132     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03133     Created:    27/1/97
03134 
03135     Inputs:     RecordTag   - the tag to write this record under
03136                 ExtraBytes  - The number of extra bytes of information the caller
03137                               will write into the record after caling this function
03138                               (Space for this many extra bytes will be reserved by
03139                               this function when it creates the new file record)
03140                               This may be 0 or more bytes.
03141                 pFilter     - The filter to write to
03142 
03143     Returns:    NULL if it failed, else a pointer to a record which saves the state
03144                 of this valueFunction object. Once the caller has written the record,
03145                 they MUST DELETE it.
03146 
03147     Purpose:    Saves a ValueFunction object to a Xara file.
03148                 This function will create a new variable-sized record with the given
03149                 record tag, and will write out whatever data is needed to save this
03150                 ValueFunction's state to the file.
03151                 
03152                 "ExtraBytes" bytes will be added to the record size to reserve space
03153                 at the end of the record for the caller to add their own data. This
03154                 is to allow ValueFunctions to be saved embedded in other object's
03155                 record structures (e.g. inside different types of attributes).
03156 
03157                 All ValueFunction record data has 3 sections, whiich are recorded as follows:
03158                 1. ValueFunction header, identifying which type of VF is being saved
03159                         INT32 ValueFunctionUniqueID     (4 bytes)
03160                 2. Derived-class-data (0 or more bytes). This particular class adds:
03161                         UINT32 NumTableEntries
03162                         + n entries of the form:
03163                             UNIT16 Position
03164                             UINT16 Pressure             (4 + (NumTableEntries*4) bytes)
03165                 3. Caller data. This is written by the caller to the returned record
03166                    object. This data must be ExtraBytes (0 or more) bytes in length.
03167 
03168                 The Position & Pressure values are 16-bit unsigned values between
03169                 0 & 65535. These represent floating point values between 0.0 & 1.0,
03170                 i.e. are simply a (UINT16) (Value * 65535.0). I don't bother avoiding
03171                 rounding errors, as 1/128000th is an insignificant error.
03172 
03173     SeeAlso:    ValueFunctionPressure::CreateAndReadFileRecord;
03174                 ValueFunction::CreateAndWriteFileRecord
03175 
03176 ******************************************************************************************/
03177 
03178 CamelotFileRecord *ValueFunctionPressure::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes,
03179                                                             BaseCamelotFilter *pFilter)
03180 {
03181     ERROR3IF(pFilter == NULL, "Illegal NULL param");
03182     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord");
03183 
03184     // Calculate how many bytes of information this VF will write. We do not include
03185     // the header info written by the base class or the ExtraInfo desired by the caller -
03186     // the base class adds all that in for us.
03187     const INT32 MyRecordSize = 4 + (4 * NextFree);
03188 
03189     // Create an appropriate record, and write our data to it
03190     CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter);
03191 
03192     if (pRec != NULL)
03193     {
03194         BOOL ok = TRUE;
03195         if (ok)     ok = pRec->WriteUINT32((UINT32) NextFree);
03196 
03197         for (INT32 i = 0; (i < NextFree) && ok; i++)
03198         {
03199             if (ok)     ok = pRec->WriteUINT16((UINT16) (pArray[i].Position * 65535.0));
03200             if (ok)     ok = pRec->WriteUINT16((UINT16) (pArray[i].Pressure * 65535.0));
03201         }
03202 
03203         if (!ok)            // If we failed, clean up & return NULL
03204         {
03205             delete pRec;
03206             pRec = NULL;
03207         }
03208     }
03209 
03210     return(pRec);
03211 }
03212 
03213 
03214 
03215 /******************************************************************************************
03216 
03217 >   virtual ValueFunction *ValueFunctionPressure::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
03218 
03219     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03220     Created:    27/1/97
03221 
03222     Inputs:     pInputRecord - The file record to read
03223 
03224     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
03225                 whatever was saved in that record.
03226 
03227     Purpose:    Loads a ValueFunction object from a record which was saved into a file
03228                 using the WriteFileRecord call. This is called by the base class
03229                 loader routine ReadFileRecord, which finds an appropriate instance
03230                 of a derived class to call to load the data in question.
03231 
03232                 This method creates a new instance of this particular ValueFunction class
03233                 and then loads whatever information is necessary from the file to 
03234                 initialise itself properly. The record read-pointer is left pointing
03235                 at the end of the ValueFunction-saved data so that the caller can continue
03236                 reading their extra bytes of data after loading the ValueFunction.
03237 
03238     SeeAlso:    ValueFunctionPressure::WriteFileRecord
03239 
03240 ******************************************************************************************/
03241 
03242 ValueFunction *ValueFunctionPressure::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
03243 {
03244     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
03245 
03246     UINT32 NumEntries = 0;
03247     pInputRecord->ReadUINT32(&NumEntries);
03248 
03249     ValueFunctionPressure *pValFunc = CreateInstance();
03250 
03251     if (pValFunc != NULL && NumEntries > 0)
03252     {
03253         // Make the array big enough to hold all the entries, to save reallocing it as we go,
03254         // and also to save us having to check for failure on each pressure item we add.
03255         if (!pValFunc->ExpandArray(NumEntries))
03256         {
03257             delete pValFunc;
03258             return(NULL);
03259         }
03260 
03261         UINT16 Position;
03262         UINT16 Pressure;
03263 
03264         for (UINT32 i = 0; i < NumEntries; i++)
03265         {
03266             pInputRecord->ReadUINT16(&Position);
03267             pInputRecord->ReadUINT16(&Pressure);
03268             pValFunc->AddPressure(  ((float)Position) / (float) 65535.0,
03269                                     ((float)Pressure) / (float) 65535.0);
03270         }
03271     }
03272 
03273     return(pValFunc);
03274 }
03275 
03276 
03277 
03278 /******************************************************************************************
03279 
03280 >   virtual ValueFunctionPressure *ValueFunctionPressure::CreateInstance(void)
03281 
03282     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03283     Created:    27/1/97
03284 
03285     Returns:    NULL if it failed, else a pointer to new ValueFunctionPressure object of
03286                 the same type as "this" one. Used to allow derived Pressure classes to
03287                 use all the base class code, and merely override the GetValue method.
03288 
03289     Purpose:    Creates a new blank object of the same type as this one. Internal
03290                 function used in ValueFunctionPressure & ValueFunctionPressureS.
03291 
03292     Notes:      Called by ValueFunctionPressure::Clone and CreateAndReadFileRecord,
03293                 as this is the only action in those functions that depends on the type
03294                 of the class that is being used
03295 
03296 ******************************************************************************************/
03297 
03298 ValueFunctionPressure *ValueFunctionPressure::CreateInstance(void)
03299 {   
03300     return(new ValueFunctionPressure);
03301 }
03302 
03303 
03304 
03305 
03306 
03307 
03308 
03309 
03310 /******************************************************************************************
03311 
03312 >   virtual double ValueFunctionPressureS::GetValue(double Position)
03313 
03314     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03315     Created:    31/1/97
03316 
03317     Inputs:     Position - A value between 0.0 and 1.0
03318     Returns:    A value representing the recorded pressure at the given Position.
03319 
03320     Purpose:    To read the value of this function at a given position
03321 
03322     Notes:      This determines the 2 closest position values for which pressure
03323                 information was recorded, and interpolates the values by "fitting a
03324                 curve" through the points.
03325 
03326                 The "curve" may be improved in future, but is currently a simple
03327                 linear interpolation.
03328 
03329                 ****!!!!TODO: This could cache the last array index it was asked for,
03330                 and start the search from that index, as we usually ask for values for
03331                 sequential, close, position values, and this will reduce the
03332                 searching overhead in most cases. Note that we may step through
03333                 positions in both positive & negative directions, so it will have
03334                 to handle this carefully. Note that PressureS functions seldom have
03335                 very many samples recorded in their tables, due to my wonderfully
03336                 rampant smoothing, so this may not turn out to be very beneficial.
03337 
03338 ******************************************************************************************/
03339 
03340 double ValueFunctionPressureS::GetValue(double Position)
03341 {
03342     // No entries have been recorded!
03343     if (NextFree < 1)
03344         return(0.0);
03345 
03346     // If the position is outside the range in our table, return the closest entry
03347     if (Position <= pArray[0].Position)
03348         return(pArray[0].Pressure);
03349 
03350     if (Position >= pArray[NextFree-1].Position)
03351         return(pArray[NextFree-1].Pressure);
03352 
03353     // Search to find the closest 2 array entries to the position
03354     // We assume the array fills the 0.0 to 1.0 range, so we search from the closest
03355     // "end" of the array to halve the average search time.
03356     INT32 i;
03357     if (Position >= 0.5)
03358     {
03359         i = NextFree;
03360         while (i > 1 && Position < pArray[i-1].Position)
03361             i--;
03362     }
03363     else
03364     {
03365         i = 1;
03366         while (i < NextFree && Position > pArray[i].Position)
03367             i++;
03368     }
03369 
03370     ERROR3IF(i < 1 || i >= NextFree, "I've screwed up the scanning loop code (1)");
03371     ERROR3IF(Position < pArray[i-1].Position || Position > pArray[i].Position,
03372                                       "I've screwed up the scanning loop code (2)");
03373 
03374     // Otherwise, the position lies between array elements [i-1] and [i], so we
03375     // interpolate between these positions
03376     ERROR3IF((pArray[i].Position - pArray[i-1].Position) <= 0.0, "Pressure array is non-ascending!");
03377     double MixValue = (Position - pArray[i-1].Position) /
03378                         (pArray[i].Position - pArray[i-1].Position);
03379 
03380     // And convert the linear mix value into a nice S-curve (180 degrees of sine wave)
03381     // We use a different function on the first and last segments so that you get nicer
03382     // ends to your strokes. (90 degrees of sine wave)
03383     if (i < 2 || i >= NextFree - 1)
03384         MixValue = cos(-MixValue * (Pi / 2.0));
03385     else
03386         MixValue = (cos(MixValue * Pi) + 1.0) / 2.0;
03387 
03388     return((MixValue * pArray[i-1].Pressure) + ((1.0 - MixValue) * pArray[i].Pressure));
03389 }
03390 
03391 
03392 
03393 /******************************************************************************************
03394 
03395 >   virtual ValueFunctionPressure *ValueFunctionPressureS::CreateInstance(void)
03396 
03397     Author:     Jason_Williams (Xara Group Ltd) <camelotdev@xara.com>
03398     Created:    31/1/97
03399 
03400     Returns:    NULL if it failed, else a pointer to new ValueFunctionPressure object of
03401                 the same type as "this" one. Used to allow derived Pressure classes to
03402                 use all the base class code, and merely override the GetValue method.
03403 
03404     Purpose:    Creates a new blank object of the same type as this one. Internal
03405                 function used in ValueFunctionPressure & ValueFunctionPressureS.
03406 
03407 ******************************************************************************************/
03408 
03409 ValueFunctionPressure *ValueFunctionPressureS::CreateInstance(void)
03410 {   
03411     return(new ValueFunctionPressureS);
03412 }
03413 
03414 
03415 
03416 
03417 
03419 // ValueFunctionSmoothStroke classes
03421 
03422 
03423 /******************************************************************************************
03424 
03425 >   ValueFunctionSmoothStroke::ValueFunctionSmoothStroke()
03426 
03427     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03428     Created:    10/10/2000
03429 
03430     Purpose:    Constructor
03431 
03432 ******************************************************************************************/
03433 
03434 ValueFunctionSmoothStroke::ValueFunctionSmoothStroke(double newValue1y, double newValue2x, double newValue2y, double newValue3x, double newValue3y, double newValue4y)
03435 {
03436     Value1y = newValue1y;
03437     Value2x = newValue2x;
03438     Value2y = newValue2y;
03439     Value3x = newValue3x;
03440     Value3y = newValue3y;
03441     Value4y = newValue4y;
03442 }
03443 
03444 ValueFunctionSmoothStroke::~ValueFunctionSmoothStroke()
03445 {
03446 }
03447 
03448 /******************************************************************************************
03449 
03450 >   virtual BOOL ValueFunctionSmoothStroke::IsDifferent(ValueFunction *Other)
03451 
03452     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03453     Created:    10/10/2000
03454 
03455     Inputs:     pOther - Another ValueFunction object to compare this one to
03456 
03457     Returns:    TRUE if the objects are considered different,
03458                 FALSE if they are considered identical
03459 
03460     Purpose:    Comparator.
03461                 Determines if 2 different ValueFunction objects are considered
03462                 different.
03463 
03464     Notes:      Calls the base class to see if they are different classes,
03465                 and then compares identical classes by checking member vars
03466 
03467 ******************************************************************************************/
03468 
03469 BOOL ValueFunctionSmoothStroke::IsDifferent(ValueFunction *pOther)
03470 {
03471     if (ValueFunction::IsDifferent(pOther))
03472     {
03473         return(true);
03474     }
03475         // Both objects are instances of this class, so compare them more carefully
03476         return( (Value1y != ((ValueFunctionSmoothStroke *)pOther)->Value1y) ||
03477                 (Value2x != ((ValueFunctionSmoothStroke *)pOther)->Value2x) ||
03478                 (Value2y != ((ValueFunctionSmoothStroke *)pOther)->Value2y) ||
03479                 (Value3x != ((ValueFunctionSmoothStroke *)pOther)->Value3x) ||
03480                 (Value3y != ((ValueFunctionSmoothStroke *)pOther)->Value3y) ||
03481                 (Value4y != ((ValueFunctionSmoothStroke *)pOther)->Value4y) ) ;
03482 }
03483 
03484 
03485 /******************************************************************************************
03486 
03487 >   virtual CamelotFileRecord *ValueFunctionSmoothStroke::WriteFileRecord(INT32 RecordTag,
03488                                             INT32 ExtraBytes, BaseCamelotFilter *pFilter)
03489 
03490     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03491     Created:    10/10/2000
03492 
03493     Inputs:     RecordTag   - the tag to write this record under
03494                 ExtraBytes  - The number of extra bytes of information the caller
03495                               will write into the record after caling this function
03496                               (Space for this many extra bytes will be reserved by
03497                               this function when it creates the new file record)
03498                               This may be 0 or more bytes.
03499                 pFilter     - The filter to write to
03500 
03501     Returns:    NULL if it failed, else a pointer to a record which saves the state
03502                 of this valueFunction object. Once the caller has written the record,
03503                 they MUST DELETE it.
03504 
03505     Purpose:    Saves a ValueFunction object to a Xara file.
03506                 This function will create a new variable-sized record with the given
03507                 record tag, and will write out whatever data is needed to save this
03508                 ValueFunction's state to the file.
03509 
03510 ******************************************************************************************/
03511 
03512 CamelotFileRecord *ValueFunctionSmoothStroke::WriteFileRecord(INT32 RecordTag, INT32 ExtraBytes,
03513                                                             BaseCamelotFilter *pFilter)
03514 {
03515     ERROR3IF(pFilter == NULL, "Illegal NULL param");
03516     ERROR3IF(ExtraBytes < 0, "Stupid ExtraBytes request in ValueFunction::WriteFileRecord");
03517 
03518     const INT32 MyRecordSize = 24;
03519 
03520     // Create an appropriate record, and write our data to it
03521     CamelotFileRecord *pRec = CreateAndWriteFileRecord(RecordTag, MyRecordSize, ExtraBytes, pFilter);
03522 
03523     if (pRec != NULL)
03524     {
03525         BOOL ok = TRUE;
03526         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value1y);
03527         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value2x);
03528         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value2y);
03529         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value3x);
03530         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value3y);
03531         if (ok)     ok = pRec->WriteFLOAT((FLOAT) Value4y);
03532 
03533         if (!ok)            // If we failed, clean up & return NULL
03534         {
03535             delete pRec;
03536             pRec = NULL;
03537         }
03538     }
03539 
03540     return(pRec);
03541 }
03542 
03543 
03544 /******************************************************************************************
03545 
03546 >   virtual ValueFunction *ValueFunctionSmoothStroke::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
03547 
03548     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03549     Created:    10/10/2000
03550 
03551     Inputs:     pInputRecord - The file record to read
03552 
03553     Returns:    NULL if it failed, else a pointer to new ValueFunction object representing
03554                 whatever was saved in that record.
03555 
03556     Purpose:    Loads a ValueFunction object from a record which was saved into a file
03557                 using the WriteFileRecord call. This is called by the base class
03558                 loader routine ReadFileRecord, which finds an appropriate instance
03559                 of a derived class to call to load the data in question.
03560 
03561 ******************************************************************************************/
03562 
03563 ValueFunction *ValueFunctionSmoothStroke::CreateAndReadFileRecord(CXaraFileRecord *pInputRecord)
03564 {
03565     ERROR3IF(pInputRecord == NULL, "Illegal NULL param");
03566 
03567     float newValue1y = 0.0;
03568     float newValue2x = 0.0;
03569     float newValue2y = 0.0;
03570     float newValue3x = 0.0;
03571     float newValue3y = 0.0;
03572     float newValue4y = 0.0;
03573 
03574     pInputRecord->ReadFLOAT(&newValue1y);
03575     pInputRecord->ReadFLOAT(&newValue2x);
03576     pInputRecord->ReadFLOAT(&newValue2y);
03577     pInputRecord->ReadFLOAT(&newValue3x);
03578     pInputRecord->ReadFLOAT(&newValue3y);
03579     pInputRecord->ReadFLOAT(&newValue4y);
03580 
03581 
03582     ValueFunctionSmoothStroke *pSStroke = CreateInstance();
03583     if (pSStroke != NULL)
03584     {
03585         pSStroke->Value1y = newValue1y;
03586         pSStroke->Value2x = newValue2x;
03587         pSStroke->Value2y = newValue2y;
03588         pSStroke->Value3x = newValue3x;
03589         pSStroke->Value3y = newValue3y;
03590         pSStroke->Value4y = newValue4y;
03591     }
03592 
03593     return(pSStroke);
03594 }
03595 
03596 
03597 /******************************************************************************************
03598 
03599 >   virtual ValueFunctionSmoothStroke *ValueFunctionSmoothStroke::CreateInstance(void)
03600 
03601     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03602     Created:    10/10/2000
03603 
03604     Returns:    NULL if it failed, else a pointer to new ValueFunctionSmoothStroke object of
03605                 the same type as "this" one.
03606 
03607 ******************************************************************************************/
03608 
03609 ValueFunctionSmoothStroke *ValueFunctionSmoothStroke::CreateInstance(void)
03610 {
03611     //You shouldn't really be calling this base class CreateInstance() so Fail!
03612     return NULL;
03613 }
03614 
03615 
03616 /******************************************************************************************
03617 
03618 >   virtual INT32 ValueFunctionSmoothStroke::GetMinimumRecursionDepth(void)
03619 
03620     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03621     Created:    9/10/2000
03622 
03623     Purpose:    Overriden function to indicate to the path stroker how many recursions to
03624                 perform at minimum before declaring a line segment 'flat' enough
03625 
03626 ******************************************************************************************/
03627 
03628 INT32 ValueFunctionSmoothStroke::GetMinimumRecursionDepth()
03629 {
03630     return 2;
03631 }
03632 
03633 
03634 
03635 /******************************************************************************************
03636 
03637 >   virtual double ValueFunctionSmoothStroke::GetValue(double Position)
03638 
03639     Author:     Priestley (Xara Group Ltd) <camelotdev@xara.com>
03640     Created:    10/10/2000
03641 
03642     Inputs:     Position - A value between 0.0 and 1.0
03643     Returns:    A value (between Value1 and Value2 given in the constructor) representing
03644                 the value of the function at the given Position.
03645 
03646     Purpose:    To read the value of this function at a given position
03647 
03648 ******************************************************************************************/
03649 
03650 double ValueFunctionSmoothStroke::GetValue(double Position)
03651 {
03652     //Which ValueFunction are we looking at?
03653     INT32 index = (INT32)GetUniqueID();
03654     index -= (INT32)ValueFunctionID_BevelEnds + 1;
03655 
03656 
03657     INT32 counter;
03658 
03659     //Find the first xvalue which is greater than or equal to our position
03660     for (counter = 0; counter < 256; counter++)
03661     {
03662         if (xvalue[index][counter] >= Position)
03663         {
03664             //Stop looking through the array when we have found it!
03665             break;
03666         }
03667     }
03668         
03669     if (counter > 0)
03670     {
03671         counter -= 1;
03672     }
03673 
03674     //Work out how far through between xvalue[counter] and xvalue[counter+1] we are, then multiply
03675     //this by the vertical difference of the two coordinates, then add on yvalue[counter] to get the
03676     //approximate value at this Position...
03677     double xdifference = xvalue[index][counter+1] - xvalue[index][counter];
03678     double ydifference = yvalue[index][counter+1] - yvalue[index][counter];
03679 
03680     //Now just check to make sure that we aren't about to divide by zero!
03681     if (xdifference == 0.0)
03682     {
03683         //Set to a very small number...
03684         xdifference = 0.0000000000000001;
03685     }
03686 
03687     double value = yvalue[index][counter] + (((Position - xvalue[index][counter]) / xdifference) * ydifference);
03688 
03689     return value;
03690 }
03691 
03692 
03693 
03694 
03695 void ValueFunctionSmoothStroke::MakeTable()
03696 {
03697     //Which ValueFunction are we creating tbe table for?
03698     INT32 index = (INT32)GetUniqueID();
03699     index -= (INT32)ValueFunctionID_BevelEnds + 1;
03700 
03701 
03702     //Make the four control points of the Bezier...
03703     DocCoord p1;
03704     p1.x = 0; p1.y = INT32(Value1y*100000);
03705     DocCoord p2;
03706     p2.x = INT32(Value2x*100000); p2.y = INT32(Value2y*100000);
03707     DocCoord p3;
03708     p3.x = INT32(Value3x*100000); p3.y = INT32(Value3y*100000);
03709     DocCoord p4;
03710     p4.x = 100000; p4.y = INT32(Value4y*100000);
03711 
03712     //Create the Bezier curve path denoted by the four control points
03713     Path strokePath;
03714     strokePath.Initialise();
03715     strokePath.InsertMoveTo(p1, NULL);
03716     strokePath.InsertCurveTo(p2, p3, p4, NULL);
03717 
03718     //Find out how long the path is...
03719     double pathlength = strokePath.GetPathLength();
03720     DocCoord* pPoint = new DocCoord;
03721 
03722     TRACEUSER( "Matt", _T("\nStarting to make Bezier table...\n"));
03723     for (INT32 counter = 0; counter < 256; counter++)
03724     {
03725         //At even intervals along the length of the curve, record the x and y coordinate
03726         MILLIPOINT Distance = (INT32(pathlength)/256)*counter;
03727         strokePath.GetPointAtDistance(Distance, pPoint, NULL, NULL);
03728 
03729         xvalue[index][counter] = double(pPoint->x) / 100000.0;
03730         yvalue[index][counter] = double(pPoint->y) / 100000.0;
03731 
03732 //      TRACEUSER( "Matt", _T("xvalue[%d] = %f; yvalue[%d] = %f;\n"),counter,xvalue[counter],counter,yvalue[counter]);
03733     }
03734     TRACEUSER( "Matt", _T("Finished table...\n\n"));
03735 
03736     delete pPoint;
03737 }

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